Thoughts on Mobile Web Best Practices...
It has been reported in several places that this year will definitely be the year of the mobile web, and thus, it is only fitting that the W3C has released a draft of the Mobile Web Best Practices 1.0 on Friday. And while there is a good number of advice that is particular to mobile browsing (many of which dovetail nicely with my own complaints), I find that most of the content could be summarized by design with web standards.
What is nice about this best practices is that it starts off by discussing some of the requirements, one of these includes highlighting user’s goals, where there is more focused browsing than on a desktop. I agree with this completely, especially since a desktop computer typically has tabs or windows where you can open content. Most mobile web browsers do not have this ability, or in browsers such as Minimo, it is not as easily used as on a desktop.
But in reality, this is not the only or even most important of the issues. The major issue is that a good number of sites render horribly in the mobile web browsers, such as making a paragraph that is one centimeter (or one word, which ever is greater) wide and billions of lines long, surrounded by inches and inches of pure white, unused screen real estate. I think this curves my own browsing techniques to looking for particular information.
Two other issues that are highlighted are advertising and scrolling, both of which I would personally group together. Most of the scrolling that is required when browsing on a mobile device is related to advertising, where many of the advertisements cause substantial vertical scrolling in order to get to the content that you are actually interested in. One such site is PocketPC Thoughts, where if you choose the Pocket Internet Explorer One-Column layout, you are forced to scroll 80% downwards to get the content of the site.
Advertising is not the only cause of this unnecessary scrolling, but it one of the major offenders. Another group in this list are sites that use a predefined size for a div, but on mobile devices, this renders into a very skinny, long column, such as many blogs, including Asa’s blog.
Navigation is a huge one. Similar to desktops, frames should simply be avoided. For example, last week I was tracking the arrival time of my wife’s flight on Jet Blue, and I thought it was rather cool that she was going to be about 20 minutes early. I later checked the site by simply reloading the site in Firefox on my desktop, and that is when I noticed that they used frames, so instead of seeing that instead of being 20 minutes early, she was just going to be on-time, I was redirected to their start page. This is frustrating from a user experience perspective, for both refreshes and bookmarking, but on a mobile device, it gets even worst. In Pocket Internet Explorer, it usually ends up that the main content frame is the smallest frame displayed on the device; Pocket Internet Explorer deals with this by drawing huge border around each frame that allows you to (arguably) quickly resize the frames, or you can take your stylus on that frame, hold it down, and select Go To This Frame, which will focus the content that you want to read, but then you lose all the navigational content that you had previously. In other words, there is nothing that frames offer that make the user experience better; all of these techniques could be rendered with CSS and be significantly more usable and portable.
But navigation also includes buttons like Back and Forward, or even bookmarks, and the recommendations suggest that some devices do not offer these operations. I find hiding the back button a bit odd though. The Pocket Internet Explorer interface deals with this nicely, by making the back button easily accessible, and it hides the forward and refresh button under a menu. And for the few times that I have to use those buttons, I am glad they aren't using valuable screen space.
The lack of the Back, Forward, and Refresh buttons definitely changes design a bit. One of the places in the recommendations that they explicitly talk about this is in error reporting. The first part of the error reporting section is simply presentation, and it is just a matter of telling users what went wrong and what they can do about it in a language that they understand. It is still surprising to me how many web sites put these cryptic error messages that make web sites much less usable. But the other part of the error section is simply about giving the users some options of what to do with the error. Should the user press the back button and try again? If so, don't assume they have a back button, and give them something to bring them back, or even better if it relates to information in a form, do not bring them back, but rather allow them to change the erroneous input in the current page. Will a refresh help the condition? If so, give them a button or a link that will retry the link. And more importantly, give them links to bring them back to some index page based on what they are browsing or some home page, both of these options are basically to keep the users on your site.
Also related to navigation is searching. There are many sites that I do not find what I am looking for quickly, so I want to search their content to find what I am looking for. The way that many pages render on mobile devices, however, the search option can be difficult to locate and can require some scrolling. In my opinion, if your site has the ability to search, place it somewhere noticeable and towards the top of the rendered page, and this way, users will remember where the search is in the event that they want to use it (and yes, I know, this site does not follow that advise :-)).
In the adaptation section, there was some good separation between server, network, and client side adaptations. This is interesting to separate them out. A great example of a server-side adaptation is actually Google. When it detects that you are browsing from a mobile device, it throws you onto a lighter-weight web site for mobile devices. And while this is a great way to optimize for mobile devices, it is not the approach that I think the average web content developer will take, but I would love to be surprised here. I would imagine that most content developers will simply provide the content in a fashion that is, instead, friendly to most devices, only optimizing little things here and there. One aspect of Google’s approach that does not necessarily jive with the recommendations is that the URL is noticeably different, and thus, bookmarking a search that I did on my PDA will not change the presentation when I display it on a desktop, therefore, not making it transparent and compatible with the OneWeb vision.
An example of a network-side adaptation is actually Palm’s Web Pro. This web browser has the ability to use a proxy server that optimizes HTML and images for your device, and this makes a huge difference for mobile usability in my experience. Pages would load significantly faster and be far more usable when you used the proxy than when you didn’t. I would imagine that some mobile phones out there would also have a similar proxy.
Finally, examples of the client-side adaptations are numerous, but the one that I have been using the most lately is the Pocket Internet Explorer’s various views. You have the option to view the pages in its default mode, a one-column view, and a desktop view. In its normal view, you will typically have to scroll horizontally to center your content, then only have to scroll vertically, and your page is typically usable, though there are exceptions (such as the very skinny columns). In the one-column view, the page is basically manipulated to place all div’s so that they follow one another and are rendered as paragraphs. In the desktop view, the page is rendered closer to your desktop view, and therefore requires a significant amount of scrolling. The Palm Web Pro previously mentioned also has similar options.
One of the topics that is mentioned in the recommendation is access keys; I would imagine that this feature would probably be more important on phones than on PDA’s, but not having every used them, it is hard to comment on them more than this.
Globally, however, I felt like
the recommendations was like reading through Jeffrey Zeldman’s
Designing
With Web Standards, since most
of the content of the recommendations are great for any environment.
For example, designing towards web standards, avoiding tables for
presentation and using elements to structure documents instead of
focusing on presentation. The OneWeb vision is simply to
create web content that is accessible no matter what type of browser
you are using.
An example of not being specific to the mobile web are forms, in that you should only ask for the information that you need, only require what you really really need, and make the difference clear. This is nothing specific to Mobile devices. As hard as pecking in information is on some mobile devices, there are a lot of users that do not like typing.
Another great, non-specific example is making links obvious, giving users a good description about what the link will give them, and possibly more important for mobile devices, but also for browser and operating system interoperability, noting the type of content that will be downloaded if the link is not to a web page. And what about web sites that open new windows? Nevermind mobile devices: desktop users are now using enough Popup Blockers that no web-content developer should really depend on new windows opening on a desktop. And finally, short and descriptive titles are ideal in any environment, particularly that in most desktop environments, the default bookmark text is the title.
In summary, I think that the recommendations are great, and I think that most of the recommendations are simply handled by generating web sites that use web standards and just generally designing user interfaces for great user experiences, regardless of their browsing environments.
RAPI EnumFiles error...
Recently, I was working with the Open .NET Compact Framework’s Desktop.Communication Library, writing a simple program to go through the device and show me all the files and directories below a certain starting point using the API’s RAPI.EnumFiles method.
Prior to adding the recursion, this program was working great. But once I added the recursion, the program began throwing a FatalExecutionEngineError exception usually at the EnumFiles method (but not always) and what was also interesting is the fact that it would sometimes recurse 10 directories and other times hundreds. The exact wording of the exception is as follows:
FatalExecutionEngineError was detected: The runtime has encountered a fatal error. The address of the error was at 0x7a0c6df2, on thread 0x1678. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
Googling over this error did not bring up very many useful results. However, I finally fell onto the post, FileInformation buffer size is too small. I downloaded the code, downloaded the RAPI.cs version 1.2 (Username: guest, Password: guest), built the library, and viola! It appears to have solved my problem.
Strings in C++...
A few weeks ago, Danny Kalev had an interesting article about Visual C++ 8.0 hijacking the C++ standard. The gist of the article is that Visual Studio proclaims a few string manipulation methods as deprecated, when the official standard does not. There are two things that I could not help wonder while I was reading through these articles though.
I find it interesting to have
this entire controversy on the various string manipulation functions.
If you look at strings from the perspective of an array of characters,
the problem they are trying to solve is already solved in newer
programming languages, such as Java and C#. The question of whether an
array is shorter or longer than the other in these languages
effectively boils down to calling array.length.
This in actuality removes not only the requirement of passing in this
argument, but it also prevents from you from lying about how long your
strings actually are. Everyone that has been programming for any period
of time knows that the length of that array will change at one point or
another, and unfortunately, there will be at least one area in the
program that makes some assumption of how large or small that array is
no matter how careful you actually are.
This, however, is unlikely to be added to C++, as the technique is quite powerful and useful in many cases, not to fail to mention that it may be quite painful to add at this time. But to quote the Spiderman movie, “with great power comes great responsibility,” in this case, the responsibility to know and honor the bounds of an array.
Regardless of that, the other
aspect that prevents this entire class of error without changing the
language is simply by using the std::string
class, as this class manages the memory and particularly, the length of
the string for you. It is not to say that
this class is not without faults, or at least perceived
faults. For one, there is no way to directly append an
integer to the string, which would generally lead to code like this:
- std::string myString = ...;
- int value = ....;
- char str[25];
- snprintf( str, sizeof( str ), "%d", value );
- myString += str;
This is unfortunate.
Java and C# have both addressed this issue, both from having automatic
conversion from objects to Strings (making the above myString
+= value;) and also
having formatters directly in the string object.
In addition to the
perceived
missing functionality (most developers will be able to quickly tell you
at least one more function that they think should have been included in
std::string),
one major concern with the string class is its dynamic memory
allocations. Interestingly enough, however, the introduction
to Effective
C++ suggests some excellent
advice: “As a programmer, you
should use the standard string
type whenever you need a string object. ... As for raw char*-based
strings, you shouldn't use those antique throw-backs unless you have a
very
good reason. Well-implemented string
types can now be superior to char*s
in virtually every way--including efficiency.” And this
excellent quote is from the Second Edition (1998). Of course,
there are reasons where you may not want the
std::string
class, but in those cases, you should use a class that abstracts out
the optimizations you require.
In addition to this, Item 13 of
Effective
STL suggests to prefer std::string
and std::vector
to dynamically allocated arrays, suggesting that they hide many of the
intricacies of dealing with pointers, and further, mentions how some
implementations of std::string
employ a reference counted and
Copy-On-Write semantics that could limit the number of allocations for
certain usage, which is further described in Item 15.
A couple years ago, Andre
Alexandrescu wrote an article
in CUJ's
Expert Forum describing
his experience with std::string.
He was asked to improve the
performance of an application, and it was believed that the issue was
with memory allocations. A little profiling lead him to believe that
strings were part of the issue, so rather than rip them out, he instead
decided to provide some policies to the classes, thus depicting how
they were being used. This significantly improved the applications
performance within a couple weeks of work.
All of this to say that the
std::string
class leads to code that is more readable, performs
nicely, and should you encounter some issues on your platform, you
could potentially upgrade your STL implementation or roll your own
string-classes.
While declaring functions deprecated that are not deprecated in the standard is a bit extreme, I think that this brings awareness to the seriousness of this issue and should developers pay attention to the warnings, it could yield more secure and stable software.
Of Hacks and Keyboards...
I am not sure if I missed something or not, but I am completely surprised at this conversation about being notified when a tab changes in a TabControl. I am surprised that no one has mentioned TabIndexChanged event or, if you are working on a platform that does not support that event (such as Windows CE), the SelectedIndexChanged event.
But what is even more surprising to me is that, not only did someone suggest setting up a mouse event handler to be notified when the user selects the tab, the original author had actually tried it! Fortunately, it seems that this does not work.
From a usability perspective, what about the keyboard? While most people use a mouse for selecting tabs, some people use the keyboard, and depending on what happens when the event occurs, the user experience of the keyboard user would be different than that of the mouse user. Debugging this over e-mail could be rather amusing, to say the least.
When creating hacks, you have to consider the cases for which the hack would not work, and in a user-interface, the inability to use the keyboard is definitely something that should be avoided, especially when a little further research would provide the desired and correct behaviour with minimal effort as the case above. Unfortunately, sometimes this is not the case, and for these cases, the caveats must be minimized and well understood and documented. Based on the discussion, I do not believe that this was the case for this particular issue.
Commonalities between Home Depot and .NET
In the last few weeks, I have been developing a couple tools in C#, half in Microsoft Visual Studio 2003 and the other half in Microsoft Visual Studio 2005. I maintain some of my initial reactions to C#, but I have begun to see why Kevlin Henney believes that C# is a more expressive language than Java. Take, for example, the following Java code:
- for ( String str : list ) {
- System.out.println( str );
- }
You would really have to know that this is a for-each statement or at least spending a couple seconds figuring that out the first time you see it. On the other hand, consider this C# example:
- foreach ( string str in list ) {
- System.Console.WriteLine( str );
- }
That is very obvious, and can be easily read aloud.
That said, however, this morning I read Billy Hollis’s How is the .NET Framework like Home Depot? and I couldn’t agree more. The .NET framework is not obvious when you do not know exactly what you are doing, and it can be daunting to find the answer.
I have witness this myself a couple times in the last week. For many things, you can simply Google and find enough hints to get you through the situation, but one problem I still have not solved. According to this MSDN Chat, you can implement an ActiveSync Service Provider using C# by implementing two COM interfaces, although he is unaware of anyone actually doing this, but I have not made major headway in this area after trying for a couple evenings (this is not particularly useful, BTW).
This is probably an extreme case (though you would think that C# would be a first-class citizen), but I regularly find myself knowing that I want a particular class or behaviour, but I am not sure what it is called. For example, the other day I was looking for the a map class, similar to Java's java.util.Map or C++’s std::map, and it was rather surprising to find out that this class named System.Collections.SortedList, a class that I would have assumed would have meant that the items in the list were sorted, not a list of key-value pairs, sorted by key.
One of the biggest issues with .NET is definitely the documentation. The documentation is generally brief or misleading. Some entries are simply filled with examples, such as when upgrading to 2005, the debugger will throw an InvalidOperationException if you attempt to perform an operation on a control that was created in another thread. When this occurs, it will refer you to How to: Make Cross-Thread Calls to Windows Forms Controls; the entry, however, does not describe the technique that you are employing, and the example is much longer and convoluted than it needs to be.
There are definitely some improvements in the newly released Visual Studio 2005, and while some of the things I have mentioned above will hopefully be addressed in future releases, some of them are not easily resolvable (like the Map-class), but at least they are going in the right direction.
Earlier Entries
- The Shared User Vision...
- Extending C++ and Java...
- C++'s Export revisited...
- Using Exceptions...
- PayPal Upgrade Brings Instability... But Its Back (at least most of it)
- The Passion Will Leave You...
- The Ouroboros-Like Patent System...
- The survey says Java Generics helps Code Maintainability...
- The Pattern-Based Future...
- Longhorn is a Big CLR Interpreter?