I'm working on improving the performance of my current web application project at various points. As I had already planned for a WCF interface for third-party use, I thought I'd utilise that, exposing objects as JSON-serialized strings usable by jQuery/ASP.NET AJAX.
Little did I realise that when I was coming up with my Data Framework (I chose Entity Framework) I should have thought about aspects at the other side of my project such as the User Interface as well as the more obvious aspects of scalability, performance in relation to a pragmatist view of what is needed in the "real world" (therefore, nHibernate is out).
My WCF service had an exposed service that would return a Client object (actually, an interface IClient) and return it as JSON. Simple.
No, I hit a number of issues with this.
1/ Investigations at StackOverflow indicated that Interfaces cannot be exposed through serialization. Makes sense, really, but dents my idealistic view of presenting interfaces and no conncrete objects to third-parties via my API. So I was going to have to either return my concrete object or reduce my return value to a JSON string, thereby bringing serialization "in house" and not relying on WCF to serialize it for me.
From:
[OperationContract]
[WebInvoke(Method="POST",BodyStyle=WebMessageBodyStyle.Wrapped,ResponseFormat=WebMessageFormat.Json)]
IClient GetClientJson(int clientId);
I went to:
[OperationContract]
[WebInvoke(Method="POST",BodyStyle=WebMessageBodyStyle.Wrapped,ResponseFormat=WebMessageFormat.Json)]
string GetClientJson(int clientId);
2/ This actually dodged the issue of the attribute configuration on the service itself, which was becoming a nightmare. Tweak it at the server and it breaks at the client, and vice versa. What was:
From:
[OperationContract]
[WebInvoke(Method="POST",BodyStyle=WebMessageBodyStyle.Wrapped,ResponseFormat=WebMessageFormat.Json)]
string GetClientJson(int clientId);
I went to:
[OperationContract]
[WebInvoke(Method="POST",BodyStyle=WebMessageBodyStyle.Bare,ResponseFormat=WebMessageFormat.Json)]
string GetClientJson(int clientId);
3/ Next was serializing the object into JSON. I was getting the "The type 'xxx' cannot be serialized to JSON because its IsReference setting is 'True'. The JSON format does not support references because there is no standardized format for representing references. To enable serialization, disable the IsReference setting on the type or an appropriate parent class of the type." exception. As I was essentially getting this at the client, it suggested my WCF endpoint configuration was wrong. Looking deeper, it turns out that Entity Framework objects are marked with IsReference=True, meaning the native DataContractJsonSerializer of WCF cannot serialize Entity Framework objects. I proved this by doing a manual serialization:
string jsonClient;
IClient client = GetClient(7);
DataContractJsonSerializer ser = new DataContractJsonSerializer(client.GetType());
using (MemoryStream ms = new MemoryStream())
{
ser.WriteObject(ms, client);
jsonClient = Encoding.Default.GetString(ms.ToArray());
}
return jsonClient;
4/ I needed to serialize using a different serializer, so thought I'd use the ASP.NET AJAX Serializer, which also didn't work, this time falling over the exception "A circular reference was detected while serializing an object of type xxx'." The type it was complaining about wasn't in the object so it was clearly navigating deeper into other objects to find that particular Type anyway.
5/ So now I am left with no other option but to either do it myself or use a third-party library. I'm using Json.NET, which I spotted on Scott Hanselman's blog and seems to be robust enough and simple enough for most purposes. So my code now looks like:
string jsonClient=null;
IClient client=GetClient(1);
JsonSerializer jsonSerializer = new JsonSerializer();
jsonSerializer.Converters.Add(new JavaScriptDateTimeConverter());
jsonSerializer.NullValueHandling = NullValueHandling.Ignore;
jsonSerializer.MissingMemberHandling = MissingMemberHandling.Error;
jsonSerializer.ReferenceLoopHandling = ReferenceLoopHandling.Error;
try
{
using (StringWriter sw = new StringWriter())
{
using (JsonTextWriter jtw = new JsonTextWriter(sw))
{
jsonSerializer.Serialize(jtw, client);
}
}
}
catch (Exception ex)
{
ex = ex; // have a breakpoint here so can inspect exception
}
return jsonClient;
Notice I have set ReferenceLoopHandling to ReferenceLoopHandler.Error. This is to try and catch the same Reference Count issue that ASP.NET AJAX JSON Serialization catches. (Actually this was added after realising I had StackOverflows occurring). Sure enough, I have another Reference Count issue as the Exception does get caught and the error is related to possible infinite recursion.
The JSON.NET Framework allows me to disable serializing potentially problematic objects, but this would require applying these changes to elements of code "Bhind the wall" of my API - and essentially add Web-specific functionality into a domain that is supposed to be platform agnostic. This is not an option for me.
So I appear to be stuck. Other than rendering the JSON myself through a StringBuilder, I'm pretty much stuck on this now. Maybe something will hit me in a flash of inspiration. Until then, it's good ol' StringBuilder for me.
Update: The Solution:
Thanks again due to StackOverflow, (John Saunders and Craig Stuntz) I've figured out how I'm going to do it. It's not as pretty as I would have liked, but pragmatism wins out again.
Here it is from start to finish. My UI generates an event that is picked up by some JavaScript. This runs:
var wcfProxy = new serviceProxy("../api/wcf/ClientBroker.svc/");
wcfProxy.invoke("GetClientJson", { clientId: 7 }, updateClient, updateClientError);
serviceProxy is RickStrahl's WCF wrapper, which has two callbacks, success and error (the last two parameters, respectively). The Invoke method invokes the WCF service and obtains the result. The WCF service is exposed via the Interface:
[ServiceContract(Namespace = "xxxWCF")]
public interface IClientBroker
{
[OperationContract]
[WebInvoke(Method="POST",BodyStyle=WebMessageBodyStyle.Wrapped,ResponseFormat=WebMessageFormat.Json)]
string GetClientJson(int clientId);
}
Note that the Body STyle is Wrapped. I couldn't get it working in Bare mode at all. (Despite telling me it had logged messages in the Windows Event Log, no events were to be found).
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ClientBroker : IClientBroker
{
public string GetClientJson(int clientId)
{
string jsonClient=null;
IClient client = GetClient(clientId);
var j = new { ID=client.ID, BusinessName=client.BusinessName };
JavaScriptSerializer s = new JavaScriptSerializer();
jsonClient=s.Serialize(j);
}
return jsonClient;
}
Notice I am using Anonymous Types to create a new type which is free of Entity Framework idiosyncracies.
This generates a wrapped JSON string:
{"GetClientJsonResult":"{\"ID\":7,\"BusinessName\":\"XYZ Ltd\"}"}
When returned to the client, the success callback is called:
function updateClient(o) {
eval('var z=' + o');
alert('BusinessName=' + o.BusinessName);
}
And the Business Name of the requested client is displayed.
It just goes to show that Microsoft may put all the features they like into C#, and you might very well know they are there. But you're not going to use them until you need to use them, and then you need to know that you need to use them! Variant types are, to me, an uncomfortable throwback of those bad VB days but sometimes they can prove useful when it comes to the crunch, I'm just keen on restricting my use of them to the absolute minimum so the very premise of a type-strong language is not lost.
Another stone passed.
I'm beginning to see why people dislike WCF.
I'm working on using WCF to feed an AJAX TreeView, and demos of it are FAST. However, in my debugging on my dev server I bumped into the exception:
"There can be at most one address per scheme in this collection"
The posters at http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/9e248455-1c4d-4c5c-851c-79d9c1631e21/#page:1 seem to be most vocal about the definiciencies of WCF in this respect - and they'd be right. What were Microsoft thinking? Most web applications need to respond to at least two domains to overcome the vagaries of user-inputted URLs, eg:
- www.myapp.mysite.com
- mapp.mysite.com
- myapp
Are all potentially valid patterns for accessing an internal web application. We shouldn't need workarounds to get this to work.
Removing the extra host header record fixes the issue. Surely they weren't expecting people to write their WCF services under a separate, discrete URL, like wcf.myapp.mysite.com?
For my current project, I am working on what is quite a complex user interface. I need to develop an interface that has splitter controls and can load one or more modules within each panel. Sort of like Microsoft Outlook three-panel interface. Sort of like the example below:

The screenshot shows how 3 "modules" have been loaded, one in each Pane.
I am using Telerik's RadSplitter control, which is part of their RadControls for ASP.NET AJAX and provide a great suite of components you can just drop into your project for rapidly prototyping and developing applications for the web.
The Splitter control itself is able to resize itself intelligently, so expanding the left column will automatically resize the content in the two right-hand panes. But there are two things it does not do:
- It does not (by default) operate within a "100% browser" environment - you need to encourage it to do so
- While resizing content within adjacent panes to a resized pane is pretty good, some intelligence may need to be applied when resizing richer controls such as Grids, where the data itself may be effected.
To solve the first problem, you just need to make sure your RadSplitter is set to use the full browser dimensions as such:
<telerik:RadSplitter ID="MainSplitter" runat="server" Height="100%" Width="100%" HeightOffset="35" Orientation="Horizontal" Skin="Outlook">
<!-- definition -->
</telerik:RadSplitter>
According to the established W3C guidelines, 100% is only 100% of a physically defined height of the calculated height of all containers of the item. The Splitter works exactly the same, so unless you are able to pixel-perfect resize your Splitter, you need to apply some hackery to get your Spliter to behave. Telerik show how to achieve this so I won't repeat them, but if you are having problems, make sure that EVERY container is able to resolve to a pixel-defined height. I have found that across browsers, it isn't always consistent. Therefore, I have the following jQuery to try and force the issue:
function stretchSplitter() {
var newWindowHeight = $(window).height() - 110;
$("#formPage").css("height", newWindowHeight);
$("#<%=radSplitter.ClientID %>").css("height", newWindowHeight); }
$(document).ready(function() {
$(window).bind("resize", resizeWindow);
function resizeWindow(e) {
stretchSplitter(); }
});
stretchSplitter();
This is using the standard jQuery onLoad trick to resize the splitter once the DOM is ready. I'm taking the 110 pixels off to adjust to the current offsets I need to take account of. This could be used to tweak designs across browsers.
The next problem is how to have the contents of each pane resize according to the pane's new size once resized. Mostly, this isn't an issue. Designing your content around a liquid layout should allow content to resize using standard CSS flowing. If displaying data, or particularly complex designs within one of the pane areas, however, it becomes necassary to finely control positioning.
In the screenshot above, I have a radGrid, which requires resizing to allow its VirtualScrolling to operate correctly. I'm actually trying to create a similar effect illustrated at the older radGrid demo. So resizing the pane will cause the grid to require resizing, which itself needs to go back to the server to rebind its rows. What I needed to do, however, was separate the functionality so that the usercontrol loaded into the pane doesn't know of its position in the Splitter. It may be loaded once (or more) in any Pane/location in the Splitter. So I couldn't "bind" myself to any events exposed by the host Splitter.
Thanks to jQuery (and my understanding of it as opposed to pure JavaScript), this was possible, if a little hacky.
I decided to use an <A> tag to act as an event proxy. This <A> tag would recieve a standard "onclick" event, and repeat it to any subscribers. I created a single <A> tag:
<a id="eventProxy" class="eventProxy" href="#" title="Event Proxy" style="display: none"></a>
Then, I attached an event to the RadSplitters OnClientResized event:
function radSplitter_OnClientResized(sender, args) {
var v=$('a#eventProxy').trigger(
type:'click',
subType:'splitterPaneResize',
resizedPanelID:sender.get_id(),
oldWidth:args.get_oldWidth(),
oldHeight:args.get_oldHeight(),
newWidth:sender.get_width(),
newHeight:sender.get_height() } );
When the RadSplitter pane is resized, this event is called, which creates an 'event' object and Triggers the event with type on the element found by the jQuery 'a#eventProxy'. As type is 'click', it will essentially call any handlers attached to the onclick event of the <A> tag.
Any handlers attaching to the onclick event would be dynamically built, so I couldn't just add them to the onclick="" attribute of the <A> tag. Again, I used jQuery to achieve this. In every Module that was interested or concerned with having to resize itself according to the new size of the content, I added the following jQuery:
$(document).ready(function() {
$('a#eventProxy').click(
function(event) {
switch (event.subType)
{
case 'windowClosed':
var ajaxMgr=$find("<%=AjaxManager.ClientID %>");
if (ajaxMgr) {
ajaxMgr.ajaxRequest("RebindUsersGrid");
}
break;
case 'splitterPaneResize':
if (event.resizedPanelID=='<%=ParentRadPane.ClientID %>') {
sizeUsersModule(event.newHeight); }
break;
}
});
});
Again, I'm using the jQuery onLoad technique to ensuring my DOM is ready. Note that I have a switch, which shows that I can re-use the same <A> tag for multiple types of event. I have two cases here, one for closing windows and one for performing the resizing of the Users Module - determined by splitterPaneResize. Note that I am checking to ensure the pane I am going to resize is the one I am interested in - otherwise, your panes will interact with each other. The sizeUsersModule is shown below:
function sizeUsersModule(newHeight) {
var ajxMgr=<%=AjaxManager.ClientID %>;
if (ajxMgr!=null && ajxMgr.ajaxRequest!=null)
ajxMgr.ajaxRequest('resizegrid_Height='+newHeight);
}
This simply takes the new height and calls the ajaxRequest client-side method of the RadAjaxManager. This causes a callback to the server, which runs the server-side C#:
Hook up my event in Page_Load():
AjaxManager.AjaxRequest += new RadAjaxControl.AjaxRequestDelegate(AjaxManager_AjaxRequest);
... and the event:
private void AjaxManager_AjaxRequest(object sender, AjaxRequestEventArgs e)
{
if (e.Argument.StartsWith("resizegrid_Height="))
{
string newHeightAsString=e.Argument.Substring("resizegrid_Height=".Length);
if (newHeightAsString.EndsWith("px")) newHeightAsString = newHeightAsString.Substring(0, newHeightAsString.Length - "px".Length);
int newHeight=int.Parse(newHeightAsString);
radGridUsers.Height = newHeight- 65;
}
}
In this code, I am parsing out the value (removing the 'px' which browsers such as Firefox include) and again using a known offset to be able to accurately size the grid. The grid is rebound and posted back.
Note that you would need an AjaxManager on the page to be able to achieve the AJAX elements of this, which I define programmatically:
RadCodeBlock radCodeBlock = new RadCodeBlock();
radCodeBlock.ID = "radAjaxManagerCodeBlock";
RadAjaxManager _radAjaxManager = BuildRadAjaxManager();
radCodeBlock.Controls.Add(_radAjaxManager);
Form.Controls.Add(radCodeBlock);
It's in a RadCodeBlock because it modifies the DOM so avoids the Exceptions associated with this.
And in each Module that is interested in Resizing, I have to hook up some AJAX settings (AjaxManager below is the same as _radAjaxManager above):
AjaxManager.AjaxSettings.AddAjaxSetting(AjaxManager, radGridUsers);
AjaxManager.AjaxSettings.AddAjaxSetting(radGridUsers, radGridUsers);
This just sets up the grid (radGridUsers) to use AJAX with the AJAX Manager and itself (as it tells itself to rebind).
I'd be interested to know if I have gone way out on the wrong path on this one, but it seems to be hanging together very well across all the browsers. This is very much thanks to the cross-browser functionality of Telerik's controls and jQuery.
Last night saw an impressive attendance at January's BCS event, on Test Driven and Behaviour Driven Development. This is possibly an indication of what people want from their BCSin terms of subject and engagement with the content.
The talk by Zakir Hoosen, from Fuzzelogic Solutions was very interesting, and proved to introduce the principles behind an increasingly widespread method of development to those who would otherwise not have had the opportunity to see it being used. This included myself. The concept of "Test Driven Development" was alien to my previous job, not because I didn't want to write good code, but because the organisation failed to engender the opportunity to spend time on code improvement processes. After seeing that while most people in the room were developers, only 5 or so actually used these methodologies, it made me feel slightly better that while my career had suffered as a result of the rut I had found myself I certainly wasn't on my own. In the "real world", it isn't always possible to find the time to look into design and test methodologies, let alone have the skills and time to implement them and surrounding processes.
Testing aside, a couple of interesting design principles came out of the discussion (and it was a discussion), which align with my own thoughts around best practice:
- Keep inheritance to a minimum, use Interfaces extensively. Whenever I expose any form of object (via an API or otherwise) to a public facing consumer, I always use an Interface. Not only does it provide benefits of abstraction, but it also helps in inversion of control, dependency injection, etc. It's also a great way to clarify in your own mind the true purpose of a particular class. All classes have their helper methods, but those implementing an interface are seen to be the "meat" of the class.
- Name your classes around the pattern that it is using. As mentioned above, I use Interfaces extensively, and you can't instantiate an interface (as such), so this is a great opportunity to implement Factory patterns and dependency injection. If you have a class that creates instances of an Interface, call it "Factory". For example, in one project I am working on, I have a ClientFactory, which produces IClients. It does what it says on the tin. Other patterns which naturally lend themselves well to forming part of the class name are Mediation ("ClientSearchMediator" for managing searching for Clients), Wrapping ("OutlookWrapper" for wrapping a component you can't necassarily change, for example, Microsoft Outlook) and Proxy (WCFProxy for when a class simply proxies calls between two objects or services, which may or may not include some form of translation). Unfortunately, some of the principles adopted within the .NET Framework and Visual Studio's automatic code generation don't always lend themselves to this style of naming, in particular, instead of having a ButtonObserver for the Observer pattern, you tend to get a button_Click method within your presentation class (be it a Windows Form or an ASP.NET Web Form).
The content of the talk was clearly welcomed by the group, much of whom were developers. As a developer, on an island, any opportunity I can get to see techniques I might not have been exposed to is welcome. Owen asked if we would like to see not only more sessions of this type, but also small "code camp" sessions where a developers collect and work around a topic, hammering out code together. This is a great idea. As many schemes in the US, whereby programmers congregate from all over the country to attend intensive code-athons, this has many advantages. As an island resident, I get to meet my peers in other businesses, learn about methodologies I haven't necessarily been involved in and be able to implement with guidance of someone who has already traversed the learning curve. While I was particularly pleased that my platform of choice (and language, I would sit there cringing if it was in VB.NET rather than C#!) was being used as the basis of the presentation of test/behaviour driven design techniques, this might not be so easy if we all "jump in" with our own preferences. We all have our own language, platform and coding conventions and standards so this may present a challenge, but also an opportunity to improve our platforms/coding conventions in the workplace as a result of seeing how others do it.
While this technical content was a welcome change, I do not want to see a 100% technical syllabus. I would still like to see "softer" subjects, such as the previous talks we have had on Search Engine Optimisation, social knowledge using Wikis, etc. This presents an opportunity to maybe create an additional technical channel to complement the softer content and encourage more technical professionals to attend, which can only be a good thing for the BCS as not only do members increase, but also professionalism is shared amongst peers which is what the BCS is all about.
When looking at developing new applications I always end up developing my own data layer. Largely because I do not like the dictatorial design principles spouted by the likes of ActiveRecord, nHibernate, et al. I write them according to real life situations where database design isn't as clean as it perhaps should be and there is no opportunity to make key changes, etc. And you know what, rolling your own is so much easier and much less hassle.
For my current project, though, I thought I'd try something "new" ...
I have been looking at Telerik's new OpenAccess ORM application recently. Telerik acquired the software a while back and have introduced it into their excellent value Premium RadControls product suite. The Express version is a good way to investigate if it is for you, so long as you are using it on a "free" database server such as SQLExpress, SQLLite, etc.
I thought I'd jot down some quick lessons I have learnt along the way.
Templates
My coding style does not match Telerik's code style as generated from the OpenAccess Reverse Engineering option. Whereas Telerik's generated form of a private member is in the format:
private string siteName;
My preferred style is:
private string _siteName;
There are few things more frustrating than adopting someone elses coding style, so I set about investigating how to get around this.
There are a number of templates that define how the classes are built when you Reverse Engineer, which are stored in the C:\Program Files\Telerik\OpenAccess ORM\sdk\IDEIntegrations\templates\PCClassGeneration folder (or your equivalent).
To change the private member format, you need to open all the files and look for a reference to the "$fieldName" variable. I changed this to "_$fieldName" and it generated the correct code.
It did not, however, generate the correct mappings, which are stored in the reversemapping.config and App.config files, which I had to tweak manually. I still have a forum post outstanding on this one.
Deferred Execution
If you get an "IObjectScope is closed" exception, you'll probably be doing something intelligent like creating a nice Factory Design Pattern, whereby you get your object within the IObjectScope and return it out for use by your BIZ objects. OpenAccess execution is deferred, however, which means if you access any of the properties outside of the IObjectScope context, you get the exception. So, for my factory method that Gets a Site object:
public object Get(Guid id)
{
Site site = null;
using (IObjectScope scope = Database.Get(_session.ConnectionId).GetObjectScope())
{
scope.Transaction.Begin();
using (IQueryResult result = scope.GetOqlQuery("SELECT * FROM SiteExtent").Execute())
{
if (result.Count > 0) site = (Site) result[0];
string s=site.SiteName;
}
scope.Transaction.Commit();
}
return site;
}
Note that I access the site.SiteName property and discard it. This just forces OpenAccess to perform the Get and put the Site object into memory so when I drop out of the method, I don't lose the object.
Using LINQ
Telerik say their Open Access solution is a mid point between LINQ to SQL and Entity Framework. Seems good to me, but there are a few gotchas you need to know about.
As with anything in the OpenAccess ORM (unless you are working with SQL directly), you don't work with tables, you work with Extents. The non-LINQ way of doing things int he code sample above shows the OQL query "SELECT * FROM SectionExtent". The table name is Section, but OpenAccess maps it into an Extent. The same model works when using LINQ. Before you can start using Extents in LINQ, you need to add the Telerik.OpenAccess.Query namespace.
If you're using of the Telerik products, you might want to follow @telerikbuzz on Twitter for useful information and updates.
Here's another pet hate in web bad-practice: Javascript. Javascript is a client-side scripting language that allows really useful interaction to occur with the page and the browser, thereby improving the end user experience when using a site. It's very easy to insert Javascript in a page, not so easy to do it right.
I despair when I look at many people's sites, blogs and networks due to JavaScript errors. It really spoils the experience for me. If I follow a link to a site with the promise of interesting content, I do not want to be presented with a series of JavaScript errors in order to get to that content. I'll just leave. Over the past couple of weeks, (since 1st December to be exact), I have been collecting some of the sites that have JavaScript errors on them (in Internet Explroer 7):

JavaScript errors can occur due to a number of problems, which bloggers/webmasters aren't always bothered about. From the most basic blog with a Twitter feed to advanced sites such as Facebook, the result of a Javascript error is the same: unwanted behaviour often accompanied by error messages that mean nothing to the end user.
There are a number of excellent resources for getting JavaScript snippets to add to your own site, many of them contributed to by "real" Javascript programmers more capable of handling Javascript code than me. Unfortunately, however, differing scripting dialects and runtimes mean that sometimes these scripts haven't been thoroughly tested on all browsers.
The increase in social networking, "widgets" and advertising services such as Google Adwords results in external Javascript being injected into the page in order to facilitate a particular requirement. For example, on the home page of my site is a Twitter script that gets my Twitter status from Twitter and injects it into the Document Object Model (DOM) of my home page. It's really neat. But if Twitter fails (as it regularly does) or the JavaScript doesn't work with my browser for whatever reason, I will get a JavaScript error - and it will be beyond my control. If possible, it's a good idea to pull the scripts off the remote servers and host them locally so you can react better in the case of an error.
As JavaScript essentially runs in accordance with the page load cycle, it requires that the programmer has made resources available in the right place and in the right order for scripts to run flawlessly. If the page load is disrupted somehow, then errors may be caused which could remove functionality from the page. For example, if I load invoke a script in the HEAD of a page, which relies on a control in the BODY, the control would not be rendered when the script executes, thereby generating an error. A simple error, but one which is often forgotten about particularly as network speeds get faster. It becomes easier to assume the user's page loads as fast as yours. If a script resource gets "held back" over the network for whatever reason, preceding scripts could easily fail.
There is a definite trend to making the web browser work more like a desktop application with every new web application released. Google is particularly focused on the RIA (Rich Internet Application) which uses techniques such as AJAX to create the impression of a responsive and fully functional application within the web browser. Unfortunately, the script behind these applications is bound to be very complex and errors easily creep in. Take Google Reader, it doesn't work on my copy of IE7. Take GMail, it regularly fails on IE7. The complexity of the applications is no excuse. Windows is a complex product but users will (rightly) criticise it and damn the product when it fails to work. The same should go for web sites that use faulty JavaScript. Users of Sitecore will know the powerful Content Editing environment that runs using extensive Javascript - it works fine. The only time I get JavaScript errors are when I cause them by fiddling with my browsing context (eg. Internet -> Intranet zones), etc.
I can almost hear the cries, "use Firefox 3.1" and "use Google Chrome", due to their JavaScript optimisation. Why should I? I use a browser that is easy to access and is on every machine I touch - that is IE 7, which occupies the majority of the browser market. If you write an web/JavaScript application, it should work on ALL browsers, within reason.
By "All Browsers", I mean:
- Internet Explorer 7
- Internet Explorer 6
- Firefox 2
- Firefox 3
- Safari
- Google Chrome
You'll notice that I have not included beta versions of browsers (although I do test my work on these when I believe it is relevant - ie. close to release) and I have gone back a version for the two main browsers, Internet Explorer and Firefox. If your Javascript doesn't work in all these browsers, or degrade gracefully, you really shouldn't release the code.
The JavaScript error message is a jarring experience and spoils many a site. The most attractive site can be ruined by a JavaScript error or two. Just because your browser places a little yellow triangle on the status bar indicating an error has occured in the page, doesn't mean other users have adopted the same configuration. The average user, who has stumbled on a page with a scrpt error, would not understand why certain aspects of the page are unresponsive as a result of any errors that have occured.
My view on JavaScript best practice is: not to use it. If you have to use it, make sure it is error checked and gracefully degrades functionality if required. Also, make sure that alternative functionality is available if the functionality it provides is important to the use of the site. I would struggle to find any reason for JavaScript to be on any "front-end" site, whether it is a blog, corporate site or e-Commerce outlet. Javascript should be a complement to a well designed site, which should add value to the user experience. Tickers, counters, advertisements, etc. are not essential to the content on a page.
There are few things more satisfying in using a web page than when a subtle visual cue is provided to indicate an action has been actioned. Facebook has a number of scripts that allow you to click on text to edit it and then apply it, for example, when updating your status. It's all happening client-side, with minimal AJAX. It works really well - when JavaScript is available and the script works. If for whatever reason JavaScript isn't available (maybe the browsing platform doesn't support it), there is the alternative of typing it in (in most cases) and clicking 'Post'.
Also, remember that search engines will ignore JavaScript. As I always say, your biggest user is deaf, dumb and blind, and that is the search engine. You have to treat the search engine as if it is a base-level browser as a first step of Search Engine Optimisation (SEO), then adding on additional optimisations both for SEO and user experience, which means JavaScript gets added last and does not prevent loading of the page by search engines. I have seen sites that load the next page in the navigation sequence using JavaScript and while it is all very clever in technique, it is not clever in practice. The search bots are getting cleverer all the time and there are rumours of automated JavaScript execution engines that attempt to mimic a user, but these cannot be gauranteed and therefore you should not wrap content only within JavaScript.
If I can, I always look for tried and tested components, rather then develop my own Javascript. I know my limitations, and Javascript isn't a strong point. But when I need it, I'll make sure it works, or look for a component I know will work and will have support behind it. That is why I use Telerik's RadControls for ASP.NET AJAX for situations where I need complex client-side functionality, possibly to create an RIA experience. I can pay for the components, know that the testing has already been done and assuming I do my work right, should just be able to "drop in" the components and tweak accordingly.
If you are working with JavaScript, good practice is to turn on JavaScript errors in your browser. That way, no matter what rush there is to launch a site, a script error will always be important - because it will directly annoy you everytime it happens. I turn on script debugging and error messages as part of my web work as standard, and it pays off in my site quality.
Update (23 December 2008):
This has been a popular post, and I'd like to thank Jim Connolly for his feedback. After reading this post, he checked the page about Advertising on his site and all seems well now. It's good to see that we share the same views on web site quality, as he was very prompt about addressing the issue and contacting me about it.
I'll keep this list up to date and will name and shame sites that fail to trap JavaScript issues. I encourage you to do the same, if you find a site you're struggling to use, feel free to leave a comment and I'll add it to my list.
All hail Google Chrome! Another venture from the megalopolis that is Google Corp.
Google Chrome is a new browser from Google. It has long been rumoured that they were getting closer to the browser space with each new service they offered, particularly with their alliance with Firefox. The thinking was that they'd re-badge Firefox, not bring out their own! But even Google didn't expect to launch it so soon, as the release is actually earlier than they had wanted due to a ***-up in an email by one of their senior staff.
I worry about this browser release. I see it as another way to add to their increasingly threatening hold on the corporate desktop with their below standard, half-functional and eternally-in-beta product line-up published direct from below an as yet to be discovered volcano at Mountain View. Okay, maybe I'm a little too cynical.
I have a number of issues with this browser.
Privacy is key for me, and while they may have a mantra "do no evil", that's not to say no evil is done. While they may or may not be tracking my search behaviour "to optimise and improve" my results (thanks, but I do know how to use Google operators myself to refine my searches), I am not confident that they won't be recording everything I do in their browser and aligning that with my Google Mail, my Google Search and my Google Docs to send me Google Adverts. My colleague quite rightly said that if it was open source, then such data "leaks" would be spotted by the community. But how "open source" is anything Google do? Certainly not their search engine algorithms, search appliances, etc. Android was billed as open source, but it turns out it has proprietary elements which will remain closed.
The Google web experience is increasingly JavaScript-based and, to give them their due, this was largely a reliable system. Now, however, they seem to have either gone beyond where JavaScript was meant to go or are letting their QA standards drop. Their Google Mail service, which I now feel I am a prisoner of - because it is so good, is now slow and buggy in its latest release. Google have announced they will develop their own JavaScript virtual machine that will *compile* what is an interpreted language. This will improve the Optimisation for their own applications, certainly, but at what cost for others vendors' applications? Can we be sure they won't do the old alleged Microsoft trick of putting in a few "undocumented" features? Will the "Google Experience" connected to the Google applications/GMail, etc. become limited to the Google browser, in isolation, or with a limited feature set in more popular browsers, which given their stranglehold of the 'web desktop' or 'cloud', could be anti-competitive? Having tried it on the JavaScript elements of the new www.dukevideo.com site, it FLIES. I'm looking forward to seeing how Sitecore performs.
Chrome also adds to the browser fragmentation which I thought we were getting on top of. If the various browsers didn't quite agree on things, at least the number of hacks and tweaks required for consistent operation across browsers is significantly reduced from those Netscape/IE 4 and 5 days. The key browsers today are Microsoft's Internet Explorer, Mozilla's Firefox and Apple's Safari. Opera, Konquerer and a few others nibble at the edges but even Opera only accounts for less than 1% of browser users on any of the sites I manage. (Opera is very good on mobile phones, though) The top three browsers all sort of agree on things, though there is a lot of improvements that could be made to all three to bring them closer to web standards compliance. IE is probably beyond help as it is coded to deal with poorly written pages, so has now cornered itself to some extent for a good while to come. Firefox, by common consensus, is the closest of all three to web standards. Safari uses WebKit, which Chrome has also started to use. Is there any undertaking to leave the WebKit "as is" without tweaking for their own corporate behaviour, maybe to tweak how their applications work to the further cost of web standards compliance?
Firefox is getting too large, too corporate and too centralised to be truly open source, and is losing open source fans and followers due to their increasingly centrist and controlling attitude. Regular readers will know I'm no fan of open source in a commercial environment, where accountability and contracts are important when developing a reliable and maintainable platform from which to do business. Firefox, however, is a good example of where open source has succeeded. If Google's Chrome is going to be open source, don't they fall in to the same trap as Firefox finds itself with the increasingly centrist Mozilla Foundation?
Will Google respect XHTML in their browser (and finally in their code?) They certainly don't in most of their on-line "applications". On their home page at www.google.com, they still use the <FONT> tag. Companies of any self-respecting web presence have now at least started deprecating their use of these tags in favour of the XHTML standard - it being more accessible and search-engine friendly. If they would have kept their horrid HTML3/4 markup on their own sites it would be okay, but they do insist on pushing it to respectable web sites via their IFRAME Google Ads. Hopefully, the "community" will encourage them to clean up their act.
What I do like about it is that it will partition its tabs from each other. This is ideal for me, because as a web developer, I often end up with multiple IE windows open, with their own set of tabs and sometimes a Firefox or two open. As I run fairly demanding web applications through them (Google Mail, Facebook, Sitecore), they do tend to freeze or crash - which in the supposed on-line world where all my work is in the "cloud", is intensely annoying - as I would lose any work I have been doing in those browsers when I have to forcibly quit. Seems an obvious idea, to me, to be honest.
The dragging of tabs outside of the browser area is very neat. I am disappointed in Microsoft not implementing this, to be honest. You can drag Internet Explorer's tabs around, but not out of the browser to create a new window.
Chrome also comes with a neat little debugger, which every other browser lacks. You always have to install 3rd party add-ons or extensions on to others browsers. It's "in the box" with Chrome and so far, I'm quite impressed with it. It is a lot more responsive than Firebug.
Having just tried my GMail in it, I have to say I like the more passive prompts for remembering passwords, etc. These appear at the top of the window, and don't block your browsing experience as happens with IE and Firefox, which always annoys as I often move between machines and it takes me 5 minutes to configure my browsing profile (never remember passwords, don't remind about redirects to secure sites, etc.).
Funnily enough, I thought this was quite satisfying when I wanted to find out about the Crash Control feature:

I'm often presented with the need to process nodes in Sitecore, which as they are hierarchical, can prove difficult to do other than via the Sitecore API. While the Sitecore API is excellent, it is a little cumbersome to create the environment when you only want the API for a single purpose. (eg. configuration files, required resources in the VS project, etc.). It's also quite slow when traversing down your node structure.
I've been working on a neat marketing channel to output the best selling products in a particular department within an e-Commerce site. So, in the "Bikes" department, I want to see the best sellers in that department, not any others and to do this I need to work from a particular node in Sitecore (representing the "Bikes" department) and work down on a JOIN from previously purchased items.
SQL is intrinsically not recursive, but we found the following SQL which might be of use:
WITH nodes (id, parentID, name, masterID) AS
(
SELECT id, parentID, name, masterID FROM database_sc53_Web..items WHERE id = '110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9' -- root node
UNION ALL
SELECT r1.ID, r1.parentID, convert(nvarchar(256), r2.Name + '/' + R1.Name), r1.masterID
FROM database_sc53_Web..items r1
INNER JOIN nodes r2 ON R1.ParentID = R2.id
WHERE r1.masterID IN
('E461EFA2-CAC8-4A14-93C2-6966E89AAB5B',
'34E5E086-6BE9-480A-9EE0-A9CD64F52A76'))
select * from Nodes
Basically, you create a SELECT to retrieve the root node (indicated by the comment on the fourth line), and then use the SQL 2005 WITH construct to recurse via a JOIN into itself. In the WHERE, we have also added a limit on what nodes are retrieved, by their Master ID, but this could be their TemplateID or some other field available within the Items table.
This produces output similar to:
This is from the Home node, and runs through the entire site, which is over 10,000 pages. With the filter on the Master IDs, we return 9,057 rows within 1 second. (I know the above says 10 seconds, but the database server is a remote server so this screenshot is a little inaccurate). This runs fast enough and is efficient enough on SQL to allow us to run these queries "live" without a caching layer.
Obviously, I wouldn't recommend putting this in the Sitecore databases themselves, rather a database alongside it and do a cross-database query.
Technorati Tags:
Sitecore,
SQL Server
This is something I figured out last year how to do, forgot, then struggled to figure out how I did it again! If I had blogged about it, I'd have known! Instead, the SDN Forum was kind enough to remind me.
As a Custom Field Type for this particular aspect of my web page was too cumbersome to develop within my deadline, I opted for an IFRAME Field Type, which when given a URL simply exposes a web page via which you can edit the relavant page data. Unfortunately, the default height is a miniscule 80 pixels. You can override this height, however, by:
Going to Template Manager
Opening your Template and selecting Standard Fields on the View ribbon:

Expanding the individual field tree on the left and selecting the relavant field
FInding the "style" field in the Appearance section and entering your own CSS, in my case "height: 200px".

Then, when you navigate to the Item which implements the Template, you get a nicely increased height:

I should add that you must remember to deselect Standard Fields once you are done, otherwise Saving subsequent content will override any shared fields and therefore break the link between Template > Master > Item.
A conversation I had with a designer friend today where he asked me what I thought about Flash web sites got me thinking.
Flash content might be "flash", but it is not necessarily useful, functional or usable. I'm not a great fan of Flash, but I can see it's value to the web. It provides attractive, fluent and dynamic sites and designs that have a level of interaction that is difficult to duplicate in a conventional web-site - even when using techniques such as JavaScript and, increasingly, AJAX.
Users who visit a Flash site may experience a number of effects of the Flash content that can disrupt a positive web experience, which often reduces the benefits of using Flash in the first place. When visiting a Flash site with a system or browser that does not have Flash installed, a pop-up, yellow bar or a simple failed portion of the page will be displayed. This can be frustrating, because before I can enjoy the quick-satisfaction I love about the web, I have to wait for a number of minutes while I download and install the Flash applet. This is, of course, only done once so it's annoying once per browser. I remember I recently had to help someone who was having problems with using a web site that used Flash. His browser was experiencing a HAL-9000 style internal conflict. It wanted to install the applet, but his security suite which had integrated itself into his system didn't like it so much, so caused extra confirmation windows which, quite simple, can be quite scary if you're not sure what you're doing.
Once the Flash applet has been downloaded and installed, we then have to wait for the Flash content to load. Well designed Flash content is, of course, loaded asynchronously often with attractive progress bars. Others, just make you wait. But why should I wait? I often have to go to sites and have to watch a progress bar making it's away across the site, and these are big sites - one key site is Sony Ericsson's product catalogue at http://www.sonyericsson.com/cws/products/mobilephones?cc=gb&lc=en. It even comes up with "There's a lot to load, but it's worth the wait". Well actually, it isn't. I struggle to wait for them to bring out decent and reliable phones - I don't want to add waiting for the most important page on their site to load too. If you haven't got Flash, maybe they think you're not worth the effort? Luckily my Nokia has got Flash, but I won't be browsing their site with it.
When the Flash applet has loaded, we're often presented with a beautifully designed and thought through experience. Immediate feedback is provided on mouse interaction with screen elements. Animation is smooth and can be beautifully subtle. A well designed Flash web site is a joy to use - if you're able to fully utilise and benefit from a web experience. Users who require accessibility features such as alternatives to mouse control, larger text, different colour schemes or spoken content all too often lose their experience at this point. No matter how many times they change their browser settings to affect the stylesheet, the text size or control method, the Flash applet will often sit and ignore their wishes. A real shame, because the effort that goes into a Flash applet is not insignificant and requires a paradigm shift in terms of programming. Additionally, even "able" users can struggle to shift their method of interaction to a Flash applet. For instance, I was at a corporate partner's web-site today and I was navigating their site struggling to find some content. I went on a page that was not relevant and instinctively went for the "Back" button - possibly the biggest button on most browser toolbars. I ended back at my Google search, quite frustrating as I then had to navigate back to where I was (after I had waited for the "web site" to load again).
The support of Flash is subject to a large extent to Adobe's opinion and support of a particular platform. The PC and Mac will enjoy Flash players for the forseeable future - but what about the increasing number of alternative browsers? Television browsing is growing fast - often via a games console connected to the internet. Also growing fast is mobile browsing. I am lucky that my new Nokia N95 phone supports Flash, but other phones may not. Other phones would need more memory, a better CPU and this can have a big impact on battery life. If Adobe does not believe a particular platform will "work" (which may even be down to licensing or political reasons, luckily, not something Adobe seems prone to yet), no matter the technical qualities of the device, they can choose not to implement a Flash player. Would you like to put your web-site into their hands and have them choose who can and cannot access your site?
Finally, there are the inevitable security concerns and the obligations that come with them that are passed on to you, the user. We're now at Flash 9. More features are being added each time and this will only provide greater opportunity for bugs and potential security vulnerabilities. We struggle to make sure that our operating system and browser is "patched up" already, now we have to worry about various applets inside the browser. Granted, this is usually an automatic process, but it is using my time to download and install, my bandwidth allocation which may be capped and places the responsibility on me to make sure it is up to date.
Then there are the servers. I always say Google is the most stupid, deaf, dumb and blind user that will use your site - but you want it to use it regularly. Search engines such as Google cannot use a Flash applet. Even when the "Googleplex" achieves sentient status, it will struggle to effectively index and understand a Flash applet and the content it contains in a structured and useful way suitable for indexing. When a search engine goes to your Flash site, it often sees very little. For heaven's sake, make sure that you at least include a decent <TITLE> tag and effective <META> data.
So how can you use Flash effectively?
I'm not interested in being negative for negativity's sake regarding Flash content. Flash content has it's place, and it can often create a very positive user experience, if implemented with consideration to users and search engines. I have come up with the following guidelines I like to keep in mind when people ask me about Flash.
What is Flash good at?
Recently, we've been playing with streaming high-quality video streams using as little bandwidth as possible for as cheap as possible. There are few products that can truly achieve this and have such a wide user-base as Flash. Windows Media Player is on virtually all PCs thanks to it's integration with Windows (except in Europe, of course!) but this often draws resentment from users, particularly Mac users who often need special software to view the same content. By the same token, Quicktime is available on Macs (although they realistically represent no risk to the true business user market) but PC users may resent (and I do) the repeated attempts by Apple to install iTunes and now Safari along with it. Having a "Go Pro" message everytime you close the application is also frustrating. Finally, there is Real Player, a wild thing that has little respect for your wider use of your PC. It aggressively tries to take control of all your media, constantly wants you to "register" for content and support (read "spam"), places tray icons that have no benefit to users and has effectively turned into bloat-ware. Flash, on the other hand, can handle very efficiently compressed video that can be secured and made available to users no matter what platform they may be using. It is no accident that YouTube use Flash for their video player. While no content on the web is truly secure, I was interested to learn that you can adopt some cute practices to seal up Flash video content - at least to the amateur.
Flash is good at marketing. Marketing channels such as banners were often animated GIF's which were slow to load, animated jerkily and were unattractive due to their 256-colour palette. Now, Flash is used regularly and - if well implemented - can provide a positive user experience. The silly and pointless Flash adverts that you find on sites like Facebook aside, a Flash applet can entice users in by presenting simple games, video's (the IBM ones are very popular, good ol' Gill) and elegantly designed animations. If I see a Flash video ad, I usually play it.
Flash is also great for games. So many hours have been spent playing silly, pointless but highly addictive games built in Flash. These games are great as a viral marketing tool, too. Kids love them, they're safe and they're highly interactive thanks to their ability to utilise the multimedia features of a PC.
Never wrap content up only within a Flash applet
You wouldn't keep your key web site content behind a username/password protected page, preventing your users and customers from accessing it so you shouldn't put such content only within a Flash applet. Users who cannot use Flash must be able to access the same information or functionality. Sure, it may not be as snazzy or beautiful, but some people don't have time, security-privileges to install Flash or just aren't that superficial. I'm a meat and guts person, myself. Flashy graphics has no effect on me, if I can't get at what I want, I'm off.
In providing this alternative content, you can choose to do it in two ways. You can check for Flash on the browser in some JavaScript and fail-over to static HTML if Flash isn't available, or you can present either content and ask the user to choose. But don't do a "Flash or HTML?"-style page, this has no benefit to search engines and requires an extra click for the user to access their content. A perfect solution, for me, is to try and load the Flash version and then load a small portion of the Flash content along with an option to choose the static version. This maintains a quick and attractive user experience, even if the user opts for the static version as they've not been made to wait for the full applet to load.
Flash works really well when it complements your content
Consider my hosting company's site: www.hostinguk.net. The Flash applet along the top is being used for what it is good at: creating an attractive and vibrant promotion mechanism that is central to the user's eye-line. I visit their site regularly, and this applet is used to convey latest marketing and products that are being implemented and gets my attention every time. But after a few seconds absorbing the simple content conveyed through the promotion channel, my eyes fall to the text - I want detail and there's nothing like text for providing it.
So in this case, the Flash content is complementing the site content. It is being used as a vibrant, attractive and sleek channel for conveying a marketing message but if you can't see it, you don't miss out. Additionally, it is small, so it loads fast. Search engines will ignore the Flash and attack the text on the same page, which will drive users to the page and who will see the attractive Flash applet and from that, their initial momentary impression of their browsing experience will decide whether they're likely to stick around and maybe make a purchase.
A client has recently told me that I had lost out on the development of a charity's web site to a Flash web site developer. This infuriates me, as, at the end of the day, they will end up with an attractive site but which would be difficult to find - and certainly next to impossible to find and jump straight in to the context which I want. Flash developers might not have realised it yet, but when you search in search engines, they tend to take you to the content you're after - not the first page and have you find your way through the navigation to the content - which is what a Flash site forces you to do.
In conclusion, we must also visit Silverlight, Microsoft's competitor product. Silverlight offers much the same as Flash does now, or will do in a production capacity when v2 is eventually released. Silverlight offers the developer a lot more features than it offers the user, in all honesty. It's another component that has to be installed in increasingly bloated browsers. From a user's point of view, I struggle to see any benefits. The benefits are entirely for developers, particularly those with a .NET background. The Silverlight platform has one key difference, however. It uses Javascript for it's control mechanism, and holds it's data behind web services and XML files as XAML. While not entirely useful for a search engine, at least it is something. Again, I would never advise implementing a site or part of a site entirely within Silverlight, particularly when it is such a fledgling product. It has a long way to go and while Microsoft may have a link on every page of their site, it's going to take more than that to encourage users to install it - particularly as it's use has actually slowed down key Microsoft sites such as their Download Site.
In creating animation, people (including clients) don't always consider the refresh rates of these assets. Not only can animated banners and the like be quite unattractive and annoying, they can also be quite unsafe for some users, particularly htose who are photosensitivity epileptic.
In determining whether a particular asset was in violation of guidelines, we found the site below, which analyses an animated GIF for it's photosensitivity risk.
http://tools.webaccessibile.org/test/check.aspx
What is suprising is the WCAG guidelines specified even 4 refreshes a second can be dangerous.
Well worth checking the next time you prepare a spanky new banner.
So today I have been working on my first production Silverlight application, if that is what you would call it. It will be used as a simple promotional device on the Isle of Man TT site, promoting the TT Live! service for 2008. You can see the page in action at:
http://www.iomtt.com/TT-Live.aspx
(Note: this page will only be active until 6th June 2008, which is the end of the TT period.)
For the benefit of Googlers, I've prepared some lessons learnt and observations made.
Images
Images within the Silverlight control can only be JPEG or PNG format, otherwise you get a AG_E_NOT_FOUND error. Found this out only within the Silverlight Forums. Could have pointed that out on the videos, guys!
Timing within KeyFrames
When working with KeyFrames, the KeyTime is relative to the parent Animation. For example:
<DoubleAnimationUsingKeyFrames BeginTime="00:00:15" Storyboard.TargetName="Frame4WebCams" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:05" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:05.2000000" Value="0"/>
</DoubleAnimationUsingKeyFrames>
JavaScript integration is ace!
I normally despise JavaScript, partly because there are so many pages out there on the web with JavaScript errors it is disheartening to want to inflict more bugs and unreliable scripts onto users.
I do like the way that functionality has been split out into the JavaScript element. This is in contrast to Flash, which uses a single file for both presentation and functionality. This split of functionality means that the host web page and server can interact with the control in a more logical fashion - particularly if you're a .NET developer. It also helps me improve my JavaScript!
One way I used JavaScript was to create a Replay button at the end of my little presentation.
I have a canvas for my Replay button:
<Canvas x:Name="BuyButton" Canvas.Top="145" Canvas.Left="259" Canvas.ZIndex="50"
MouseLeftButtonDown="onMouseClick">
Which calls my event handler in BLOCKED SCRIPT
function Replay_onMouseClick(sender, mouseEventArgs)
{
this.storyBoard=sender.findName("Frame1Storyboard");
this.storyBoard.begin();
}
But what I found super sexy is that I can find the storyboard that is in charge of my animation from the sender object, and just tell it to start. I found this thanks to the new JavaScript debugging in Visual Studio 2008, by the way. Not through the inspection tools, but by banging in random command lines in the Immediate window. I got lucky.
Development Experience
There is a lot of work Microsoft need to do to make the development experience more intuitive and cohesive. For instance, I have Visual Studio 2005, 2008 and Expression Studio February 2008 Beta. My VS 2005 supports Silverlight - to a point. My VS 2008 for some reason doesn't. My Expression February 2008 Beta works much better than previous versions. Overall, I end up being quite confused about what should be done where.
I'm also trying to learn the Expression product suite and bringing what I know from Flash I think I am getting to grips with it. I cannot see any of our designers using their tools, though, as I think Microsoft would wish. From what I can tell from their marketing, they are hoping for designers to generate the UI or visual components in Expression/XAML and pass the solution/projects on to the developers. These files can then be sent back and forth between departments as needed. I am not convinced this will work, however. Quite apart from anything, don't designers live in the Mac camp, beyond the ocean? ("There be dragons there")
Also, whilst the XAML produced by hand and by the tools is clean enough and well-structured, it is obviously structured according to the requirements of the presentation, rather than semantically. For example, I would have liked to highlight which TextBlocks related to headings, either by a Heading1TextBlock (being equivalent to an H1 tag) or by attribute, eg. <TextBlock HeadingLevel="1" />. This more open manner of managing content encapsulated within a Silverlight control or component does allow search engines access for indexing (unlike Flash), but doesn't give them the full semantic experience that is so important in effective indexing of content.
I must say the QuickStart videos at www.silverlight.net were essential and very useful in getting this far. If only my shouting at the presenters would have given me the answers I needed.
Don't think you can modify your XAML in Expression Blend and F5 to refresh your browser output. Doesn't work, resulting in repeated Ctrl+Refreshes to clear caches, etc. Took me a while to figure that out, too. (Visual Studio 'locks' the file, even when in "pause" mode). You do have to recompile each time.
I have found the optimal experience is having the following open and switching between the three:
- Microsoft Expression Blend - for the visual development of the XAML elements
- Microsoft Visual Studio 2008 (editing using the XAML editor, though I don't get a preview) - for the down and dirty XML tweaking and JavaScript hacking
- Adobe PhotoShop - for the graphics
One more thing; why does Expression Blend open Microsoft Word for an HTML editor by default? When will Microsoft dump their insistence that people want to develop web pages in Word, and generating the crap output that it generates? I would think any developer worth his salt would jump around in frustration if a designer modified something in the HTML editor in MS Word, wrecking their beautiful XHTML mark-up! (Okay, maybe not that beautiful).
I have just completed revisiting the checkout portion of the various e-Commerce sites I help manage. The reason for the revisit was to establish ways to improve the conversion rate of users that enter the checkout and complete the checkout to make the purchase.
Part of the testing process has highlighted some interesting points about e-Commerce checkouts and forms in general. I'll share them with you, here.
Make sure the Enter key targets the appropriate button on submission
Users can find it difficult making the transition between conventional desktop use, where Enter keys and mouse actions perform certain actions, and web use where Enter keys don't follow such stringent rules as windows and dialogue boxes and double-clicks aren't useful. (Even though users double-click on web pages an awful lot.)
One aspect of this is users' habit (and perhaps rightly so) of pressing "Enter" after finishing a particular section of a form. For example, when logging in to a site, typing:
<username>TAB<password>ENTER
to enter the requested details and actioning the request. Of course, on the web, thing's aren't so straight forward as a Windows dialogue box. This is particularly a problem for .NET sites, thanks to the way that ASP.NET renders it's pages, but a fix is available in ASP.NET 2.0. I have used the new DefaultButton attribute to achieve this:
<asp:Panel ID="pnlForceEnterKeyToLogin" runat="server" DefaultButton="btnLogin">
<fieldset>
<legend class="hidden">Login</legend>
<asp:PlaceHolder ID="plhExistingUserValidation" runat="server"></asp:PlaceHolder>
<p>
<asp:Label ID="lblExistingEmailAddress" runat="server" AssociatedControlID="txtExistingEmailAddress">Email Address:</asp:Label>
<asp:TextBox ID="txtExistingEmailAddress" runat="server" />
</p>
<p>
<asp:Label ID="lblExistingPassword" runat="server" AssociatedControlID="txtExistingPassword">Password:</asp:Label>
<asp:TextBox ID="txtExistingPassword" runat="server" TextMode="Password" />
</p>
<p>
<asp:Button ID="btnLogin" CssClass="button" runat="server" Text="Continue >" />
</p>
</fieldset>
</asp:Panel>
You'll also notice that I have used the '>' character to convey movement to the next screen. I'll probably replace this with an image shortly, but the point remains the same, small visual cues like this say more than you think.
Check page-flow is useful to the user
Make sure that page-flow from adding an item to the user's basket and putting the item in the basket is logical and obvious. There are three options, each with it's own considerations:
- Recycle the same page - Users can add items to their basket very quickly and not "lose" position in the site. This is particularly useful for pages with multiple items for purchase. However, make it obvious something has happened. Previously, I have emboldened the last item added to the basket, but a distinctive message would also suffice.
- Jump into the checkout - Once "Buy" is clicked, sending the users straight in to the checkout certainly emphises the process of purchasing, but then forces users who want to continue shopping to then come back out of the checkout to continue purchasing. It also gives a slightly forceful impression, which may reduce the number of units bought per purchase.
- Jump to a page full of other products - This is probably the most widely adopted method for companies who are more on the ball with their e-Commerce offerings. Once a product has been purchased, even basic cross sell logic could generate a series of products which may also interest the user either as a complement or otherwise to their purchase. Amazon.com do this, as do Marks and Spencer. However, again, make it clear that the user has added the item to their basket.
When errors occur, make it bloody obvious!
For complex pages, validation can be a pain in the @rs3! Where do you put the validation errors? Do you out them at the top of the page, or alongside the individual controls? I choose to put them at the top of the <FIELDSET> containing the controls, for accessibility, but this means that if the user has a particularly full basket, they may not see the errors as they may "fall off" their immediately viewable screen, resulting in the impression the page hasn't done anything when they clicked the button.
I have reinforced the messages within the <FIELDSET> by a distinctive banner that is shown at the very top of the page that advises them to look further down the page for why the request didn't work out.
Usability testing
While a fully budgetted for focus-group is an ideal thing to have to help identify niggling issues in usability, throwing the checkout at random people in the office could also be a great way of spotting errors, niggles and spelling mistakes you would never spot yourself. It can also be used as a training exercise for the support staff, such as customer services teams.
And of course, accessibility goes without saying ... doesn't it?
Even now, four years or so after it became a "good idea" to make sites accessible, developers STILL generate HTML 4 with no regard to semantic or accessible content. The same rules still apply:
- Use FIELDSET's to separate sections of a form and label them with a <LEGEND>. You don't have to display the legend, hide it if it detracts from the design.
- Use XHTML+CSS to seperate your markup and content from your design. And while you're at it, how about making a print stylesheet by using media="print" on your <LINK> tag?
- Use AccessKeys on key parts of the form, such as submission or common fields such as email address. And make sure your TabIndex works correctly.
- I like to try and reduce the number of images in the "content flow" as much as possible, unless there is a particular relationship between the adjacent content. Therefore, "furniture" such as icons, decorative elements, etc. I put in CSS. That way, a user on a light-weight browser or slow connection does not have to wait for it all to download and render (assuming you are using CSS media types).
- Don't rely on JavaScript - and definitely not Flash!
- Make sure your text is of a large enough size as to be legible. Remember that about 60% of users who use the web have some degree of eye problems.
And while I'm here, this is a really neat way of hiding content from browsers, but not hiding from speech readers:
* hidden { position:absolute; left:0px; top:-500px; width:1px; height:1px; overflow:hidden; }
The problem being that it is often required to have content within your markup, but want to hide it for design purposes as elements such as <LEGEND>s, <CAPTION>s, etc. are often targetted to specific platforms and users. Hiding it with a display: none or visibility:hidden is no good, because speech readers (being one of the specific accessible platforms) have started to implement these rules. This method, however, moves it off the content layer, then either moves it out of the rendering viewport or makes it obscenely small so as to make is invisible and (hopefully) so small that if it was rendered it wouldn't affect your overall design.
There is the unfortunate news today that five Britons have been killed in a coach crash in Ecuador (BBC News). This is tragic news, particularly for those close to the victims. While watching the news on Channel 4 News this evening, I was shocked to see the girls' Facebook page to be used as a means of identifying one of the girls who was killed.
In the days of attacks on our privacy, either by legislation or incompetence by the government, and warnings about revealing information particularly on the internet, this surely was most irresponsible.

Note that in the screengrab from Channel 4 News this evening, I have removed some very risky information:
This grab was broadcast to the entire of the UK. Malicious individuals can use this information to cause further distress or commit fraud using these details. The BBC programme Newswatch recently covered the BBC using Facebook and MySpace pages to depict individuals in the news.
It just shows that it is even more important for users to hide thier profiles from everyone except their immediate friend network. The internet is full of personal potentially private information, including sites I have written myself, and restricting the access to information that could be regarded as being subject to fraud or misuse is even more paramount. While developing these sites, I took privacy very seriously and signed up to the appropriate legislation when required, but it seems users themselves need to take as much care as the site developers - and for news agencies not to blatently broadcast the information indiscriminately in the pursuit of a 5 second grab for a news package.
This is going to be about a local issue, but no less relavant to my on-going pontification about web best practice. I hope that you'll enjoy it, even if you don't enjoy living here on The Isle of Man, as I do!
The Isle of Man nestles in between Ireland and England, and is home to major finance institutions due to it's off-shore status. Therefore, it supports a burgeoning hi-tech business community, and web design and web services has a signficant contribution. A number of web sites have sprung up, some work well enough, many more are really bad. One of the stalwarts of the island is www.isleofman.com, which is a web-site aimed at many audiences on and off the island. It forms an excellent window onto the island for the visitor and tourist, and an even better portal for the resident who needs access to local news, weather, sport or information about the island's businesses. I have had the pleasure to have had a brief contribution to the site, although this was before the recent change in ownership.
Those who know me and who read this collection of hap-hazard thoughts will know that I have a distinct idea of what counts for a quality web-site. Key words for me are simple attractive design, accessible, usable and semantic.
Let's take a look at this new site:

http://www.isleofman.com/index.aspx
Very attractive, I'm sure you'll agree. As a showcase for the island, this page really looks the business .... until you look a bit closer and start to use it. The image caraousel in the middle of the screen is a Flash component, which while attractive, is actually quite difficult to use. For example, you move your mouse anywhere within the [invisible] borders of the control (including the white areas) and pictures start to fly left and right. A neat effect, but I wouldn't be expecting that if I was concentrating on clicking the useful links at the bottom of the page. Surely the images should only move when I am concentrating (and my mouse is too) on the images themselves?
Unvelievably, those lists at the bottom of the page are not lists, in the semantic sense. They are just links within tables. Such an easy opportunity missed to present semantic and accessible content to search engines and users. I could have forgiven the use of Flash on the home page if these were written semantically, ie. as a series of UL > LI's.
As you hover over the images, you wonder what is behind them, as there is no hint as to what each image is for. No text appears to give any hint. So, maybe I should click on one to find out:
Nope, still none the wiser. Those who know the island will know we have a famous association with motorsport, particularly due to the World Famous TT Road Races, which see some of the best riders race round the public roads of the island for two weeks in the year. So, you'd be forgiven for thinking that this has something to do with the TT races - well, you'd be wrong:

http://www.isleofman.com/Tourism.aspx
This is the Tourism home page. Eight attractive photographs are presented to you, which are randomly selected each page refresh - a nice touch. Looks really attractive and usable. I would then start clicking on images to see where they go, but they go nowhere. They are not links, though they feel like links into different areas of Tourism. You'll notice I caught an ALT tag on the screenshot above - which is the same ALT tag on every image. Sort of defeats the point of an ALT tag, really. So where can I go? My eyes are drawn down to the rich content of the images and I feel lost as to where the content actually is. It takes a few moments to remember there is navigation at the top of the screen to help me.
Another cheap opportunity to be semantic and accessible would be the breadcrumb. An essential navigation aid in any medium to large site, should be implemented as it is: it is a sequential list of pages who order is important. Sounds like it should be an ordered list (OL), but it isn't.
I'm not going to spend time being overly negative, but I think I have made my point. I am a bit of a purist at times, but I am also pragmatic when it comes to the difficulties of maintaining and improving large established sites. So afterwards, how do I feel about this new look?
Firstly, the site is very attractive. The designers responsible have done a very good job of revitalising a tired design, which although attractive, was less than stimulating. I really do want to explore this site to see more of it's rich colours and imagery. But, when I can't or when I feel like I am randomly being sent around the site with no hint as to what is behind each link (the home page carousel, in particular) I feel cheated and confused. Bizarrely, the carousel isn't even consistent in the lack of information. Fair enough, a sizeable chunk of those images link through to the Tourism section - but not all of them, your challenge, dear user, is to figure out which (the Manx Flag, Celtic Dancers and Louighton Sheep link to different content). This carousel really needs a text overlay on it - then it would be complete - albeit in Flash. (Have you considered Silverlight? My bet is that it will work well with your CMS as it is XML based!)
This site has always performed very well with search engines. It has a prestigious domain name (well, if you're an islander!) and is actually often mistaken for one of the Isle of Man Governments own sites as a result of this high-ranking position in search engines. (Do a Google for "Isle of Man" and it is this site not any of the government sites that hits the top spot) As I always say, your favourite user is also your most limited user. This user cannot see colour, nor can this user appreciate design. The user cannot even make any intelligent detemination as to the meaning of the text on your page. This user is Google, et al. This is one reason why accessibility is so important, not to mention the very real and relavant audience of users who do not have the capability of obtaining the same web experience as you or me. Whether blind, deaf, wearing glasses or difficulties with motor-skills, these users are just as important. So an accessible web site, using industry best practice is essential. Simple rules like avoiding tables when they are just being used to form layouts, recording correct and meaningful text alternatives to images AND links and using semantic mark-up are the basic building blocks on which to build a site. This site breaks all those rules.
Saying that, one big no-no in accessibility is opening new windows pointlessly. In viewing this site, I had the misfortune to have to sully my new laptop with Flash to have the home page work (I wouldn't bother usually, the site did work quite well without it, though it wasn't pretty) and the link to get the Flash player did not open in a new window as per accessibility guidelines. Hooray to that!
The site is a big site, and it was always going to be a difficult task to make the transition into a new design. I love the design, I love the Celtic emblems which are remninscent of the local artist Archibald Knox (and I have a sneaking suspicion who applied that mark everywhere on the site). A lot of care has gone in the little things, unfortunately, their effect is spoilt by the use of unintuitive, and uninformative navigation controls. There were a series of other bugs and spelling mistakes, but these are not important, to me. They'll get ironed out over time. While I am sad to see my own contribution to this site go (the old on-line shop software), I am pleased with it's revitalisation and wish it and the team the best of luck.
More Posts
Next page »