s8design.co.uk

Dynamic Updates of Web Content: Taking the “X” Out of “AJAX”

This topic is not a brave or new one. It’s simply a matter that the question recurs in cyberspace, and I hope to synopsize some easy insights and not have to repeat the offering in external forums again and again (did I mention “and AGAIN”?).

For those of us who rely on JavaScript to manipulate the contents of web pages, AJAX has become a way of life. There exists a huge (and occasionally vitriolic) debate about whether XML is the preferred content delivery scheme (just type “xml vs. json” into your favorite search engine and be prepared for bombardment). This is NOT the topic of the current presentation. The underlying communication stream, based on the XMLHttpRequest object of JavaScript offers a great deal more flexibility than simply a choice of two competing content formats. In the course of being a good ‘net citizen and supplying solutions for my less geekly brethren on Yahoo!Answers (written under the “nom de guerre” richarduie), I frequently encountered questions regarding the means by which to initiate the addition of new, generic, textual content from the clent-side…AJAX anyone?

AJAX doesn’t presume any particular format of content representation. The “X” (from XMLHTTP) is, more than anything else, an unfortunate holdover from “olden tymes,” i.e., circa 2000 (which is almost forever ago in Web years), thanks to the original ActiveX implementation by the evil empire, Microsoft. We’re now pretty well stuck with the usage, but, as long it doesn’t distract you from the underlying nature of the real processes, no worries. Remember that this is plain, old HTTP request/response handling – the response stream is nothing more than text; it may contain references to more complex content, such as images or other media that the browser will be required to fetch and render, but anything that can be addressed by a URL is fair game.

Now, I grant that there are many useful JavaScript libraries already configured to provide AJAX services, e.g., prototype, Dojo, etc. Goodness knows, I’ve applied them during my days of captive employment. The rub is that these libraries frequently demand a bit more transfer bandwidth than I prefer, if my sole purpose is to provide very simple AJAX services. So, like all performance-minded geeks, I’ve written a lighter-weight object to handle the operations of AJAX-based fetching of just any old content (heck, the fully-commented, “War and Peace” version is less than 8K – stripped, it’s TINY). This places a burden on the page-specific scripting to be aware of the nature of the content and how to manage it. However, that burden may be quite trivial and differs little, if indeed any, from what would be required by the application of any other library’s AJAX-management objects. That’s just “gravy” in this context – the real meat and potatoes is the dynamic inclusion of files that were not originally in the web page on an as-needed basis without overhead for some additional “wrapper” format.

So, first, there’s my simple, light-weight XMLHttpRequest object manager:

// X(ml)H(ttp)R(equest)Wrapper Object
// define minimalist wrapper object to manage XMLHttpRequest object for
// AJAX processing to read URLs as simple, plain text
// author: S8Design by Richard.Harrison[at]s8design[dot]co[dot]uk (a.k.a., richarduie[at]yahoo[dot]com)
function XhrWrapper()
{
   // private methods - - - - - - - - - - - - - - - - - - - - - - - - -

   // utility method to abbreviate calls to getElementById() to get
   // element with id {eid}
   function get(eid) { return document.getElementById(eid); }

   // create an instance of the XMLHttpRequest object
   function createRequestObject() {
      // initialize return object in function-global scope - if neither
      // approach to creation succeeds, return {request} will be null
      var request = null;
      // minimal browser sniff - STILL can't trust native implementation
      // of XMLHttpRequest object in IE (7 or otherwise) - would prefer
      // try/catch on attempt to create native object, but that would
      // succeed in IE7+, even though the object would be "lame"
      var browser = navigator.appName;
      if('Microsoft Internet Explorer' == browser) {
         // attempt to get ActiveX versions from latest to oldest
         request = new ActiveXObject(
            'Msxml2.XMLHTTP.6.0' ||   'Msxml2.XMLHTTP.3.0' ||
            'Msxml2.XMLHTTP'     ||   'Microsoft.XMLHTTP'
         );
      }
      // use non-ActiveX, native JS implementation of XMLHttpRequest
      // object for compliant browsers, e.g., Firefox, Opera, Safari.
      else request = new XMLHttpRequest();
      return request;
   }

   // callback for all changes of ready state
   function handleStateChange() {
      switch (ajaxRequest.readyState) {
         case 0: {   // created, uninitialized - open() not yet called
            break;   // no handling at present
         }
         case 1: {   // open() called - send() method not yet called
            break;   // no handling at present
         }
         case 2: {   // send() called - responseText and -Body unavailable
            break;   // no handling at present
         }
         case 3: {   // receiving - responseText and -Body still unavailable
            break;   // no handling at present
         }
         case 4: {   // completed - all data available
            doComplete(ajaxRequest.responseText || null);
            break;
         }
         default: {
            throw name + '.handleStateChange() could not identify a valid ready state';
         }
     }
   }

   // specific handling for request completed ready state
   function doComplete(c) {
   // c...String content returned as AJAX response
      // intitialize optional, additional arguments to external function named
      // in {fnComplete} for String concatenation of arguments if they exist
      var args = '';
      // if arguments available, construct String to embed in eval() call
      if (null != fnCompleteArgs) {
         var last = fnCompleteArgs.length;
         for (var i = 0; i < last; i++) {
            args += ',' + fnCompleteArgs[i];
         }
      }
      try {
         // pass response contents and any additional arguments to external
         // function named in object variable {fnComplete}
         eval(fnComplete + '(c' + args + ')');
      }
      catch (e) {
      // since this method is private, instance name is referenced privately
         throw name + '.doComplete() failed to interpret expression:\n' +
            fnComplete + '(' + c + args + ')\n' + e.toString();
      }
   }

   // private fields - - - - - - - - - - - - - - - - - - - - - - - - -

   // object global XMLHttpRequest instance
   var ajaxRequest = null;

   // name of callback function (as seen from page scope) for onComplete
   // state - can be a reference to a public function of this object
   var fnComplete;

   // optional argument-list to be included after text contents fetched
   // by AJAX processing in call to {fnComplete} - array in argument order
   // function named in {fnComplete}
   var fnCompleteArgs = null;

   var name = 'xhr';   // set default name for instance

   // public methods - - - - - - - - - - - - - - - - - - - - - - - - -

   // get text from a URL, passing results to page-scope function
   // named in {complete}, once response processing is complete
   this.doGetText = function(url, complete, completeArgs) {
   // url............service provider address - can be a file
   // complete.......name of function in page namespace to which to pass
   //                response of AJAX request
   // completeArgs...additional arguments required by function named in
   //                {complete} - optional
      // create request object, if not yet done
      if (null == ajaxRequest) ajaxRequest = createRequestObject();
      // if still null, throw exception and abandon process
      if (null == ajaxRequest) {
         throw this.getName() + '.doGetText() failed to create valid request object';
      }
      // assign name of onComplete handler to function global holder
      fnComplete = complete;
      // if argument-list passed for call to function named in {complete}
      // assign those to holder
      if (completeArgs && null != completeArgs) fnCompleteArgs = completeArgs;
      // initiate fetch dialog
      ajaxRequest.open('get', url);
      // force content type to be plain text
      ajaxRequest.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8');
      // if not IE, overrideMimeType allows further insistence that server
      // sends plain text mime type in response
      if (ajaxRequest.overrideMimeType)
         ajaxRequest.overrideMimeType('text/plain;charset=UTF-8');
      // do this after open() to avoid IE initialization problems -
      // allows reuse of same XHR object...silly IE bug
      ajaxRequest.onreadystatechange = handleStateChange;
      ajaxRequest.send(null);   // fetch!
      return false;
   }

   // append String (in new element) to an existing element of current document
   this.appendToElement = function(c, pId, tag) {
   // c.....any String (with or without markup)
   // pId...id of parent element in page to which to append content -
   //       optional with default of body
   // tag...tag name of element to contain content to be appended -
   //       optional with default of div
      // if argument is missing or null, offer error message
      if (!c || null == c) {
         // since this method is public, instance name is referenced publicly
         throw this.getName() + '.appendToElement(): missing content to append';
      }
      // ...otherwise (implicit else), add content to page
      // default to body, if no parent element id given
      var p = (!pId || null == pId)?document.body:get(pId);
      // default to div, if no container tag name given
      var tag = (!tag || null == tag)?'DIV':tag;
      var el = document.createElement(tag);   // create new element of type {tag}
      el.innerHTML = c;                       // insert content into element
      p.appendChild(el);                      // append element to parent
   }

   // public accessors and mutators for private fields - - - - - - -

   // get AJAX request object for this instance
   this.getRequest = function() { return ajaxRequest; }

   // get String name of function in page namespace to be applied as callback
   // for completed ready state of AJAX request
   this.getFnComplete = function() { return fnComplete; }
   // set String name of function in page namespace to be applied as callback
   // for completed ready state of AJAX request
   this.setFnComplete = function(f) { fnComplete = f; }

   // get arguments for function in page namespace to be applied as callback
   // for completed ready state of AJAX request - array in argument order of
   // callback function
   this.getFnCompleteArgs = function() { return fnCompleteArgs; }
   // set arguments for function in page namespace to be applied as callback
   // for completed ready state of AJAX request - array in argument order of
   // callback function
   this.setFnCompleteArgs = function(a) { fnCompleteArgs = a; }

   // set instance name of object - default name is "xhr"
   this.getName = function() { return name; }
   // set instance name of object, if default name "xhr" is not to be used
   this.setName = function(n) { name = n; }

   // public fields - - - - - - - - - - - - - - - - - - - - - - - - -
   // none at present
}

I store this script in the file ajaxXhr.js. A simple example of the code for a test page to acquaint you with some of the concerns is:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
</style>
<script type="text/javascript" src="ajaxXhr.js"></script>
<script type="text/javascript">
   // create instance in page global scope, using default name xhr
   var xhr = new XhrWrapper();

   // testing functions
   function getUrl(type) {
      type = (!type)?'text':type;   // set default, if not given
      var url = document.getElementById('url').value;
      if ('text' == type) {
         xhr.doGetText(url, 'xhr.appendToElement');
      }
      else if ('js' == type) {
         xhr.doGetText(url, 'doJs');
      }
   }

   function doJs(c) {
      eval('var qwe = ' + c);
      alert(qwe);
   }

</script>
</head>

<body>
   <form>
      URL:
      <input type="text" id="url" />
      <input type="button" value="get file as text" onclick="getUrl('text')" />
      <input type="button" value="get file as JS" onclick="getUrl('js')" />
   </form>
</body>
</html>

The testing HTML offers two simple handling approaches; either append the retrieved content directly to the page or interpret it as a JavaScript expression. The additional overhead for using the XhrWrapper is contained in the in-page script block (could be excised and placed in some more general.js file, but this was a throw-away testing page, after all).

For instance, S8 uses this model to retrieve content for dynamically composed select/options controls. That is, in the case that there are several, successive sets of options that rely on the user's elections of earlier values, we apply the XhrWrapper object to request services from PHP scripts. The PHP services compose the HTML for the new control without additional structure ("a la" XML, JSON, etc.) for direct inclusion to the page. User selects an option in one control, and AJAX fetches the next control, with values appropriately filtered in the PHP layer based on the user's immediately previous selection. The resulting, pre-composed HTML (text) control is then added to the page (in this case, used to replace the innerHTML of a target element identified by it id attribute).

So, to sum up, whether you apply the XhrWrapper (and you are welcome to do so), your own approach, or some more heavy-weight library, fetching straight, ungarnished, textual content directly from files or services is trivial to accomplish. Look, Ma, no "X"!

Due Date Before Requirements: A Recipe for Disaster

If you stay in IT long enough, unless you are blessed with exceeding good fortune, you will encounter the situation that a customer wants something built by a deadline but isn’t sure what that something is. I lovingly refer to this as “deadline before specs,” and the emphasis is on the word “dead.”

Back in the days of my captive employment, I faced at least one of these pre-defined fiascos in each shop that I called “home.” The mainly contributory elements that each of these companies shared was a project methodology – waterfall – and a marketing-driven mindset. Each placed “blue-sky” ideas about acquiring new business ahead of any sensibility to issues of practicality with respect to implementation.

Let’s look at some of the primary ingredients of this recipe:

  1. belief that new business is the overwhelmingly most important commercial aspect
  2. belief that business units “know better” about ALL business issues
  3. belief that anybody, hearing “THE IDEA” would know EXACTLY what it required
  4. belief that IT resources are completely flexibly configurable
  5. Now, I am among the loudest to tout the notion that customers are THE reason that IT exists. Addressing the concerns of the stakeholders outside of IT is how I pay my bills (and get my thrills). I own a wide and deep experience with several industries and business models. I am not, however, so perfectly versed in the non-IT facets of business that I always automatically "see the vision" of every half-baked project idea that a marketing (or other business) person dreams up. There must be a firm and explicable grasp of the product. There must be a well-described business model. There must be a clearly defined universe of stakeholders. Lacking any of these aspects, the requirements collection process will be profoundly flawed, possibly beyond the capacity to repair.

    I don't do waterfall in my private practice. I use a modified Agile approach, just enough project management to keep the design and development train on the rails. Frequent, regular communications among team members, including the client (and any other participating stakeholders), is the byword. The customer must be able to express clearly and concisely answers to the questions:

    1. What is to be built – the product?
    2. What is the business model?
    3. Who are the stakeholders?
    4. The answers to these questions may evolve during development, as new interests and concerns are identified, but at each phase of design and development, I must own a good grasp of what those answers are TODAY. With solid replies to those questions, I can collect requirements and forge estimates of time and cost to deliver the product. Note that it is I who defines the time-lines. The client may opt to reduce the feature payload to reduce the estimated times and costs, but it remains my responsibility and authority to define the revised time-line and cost estimates. This can be the subject of many rounds of refinement. Project planning can be a multiple iterations, successive approximations game. However, the burden for determining the amount of effort and price are my bailiwick. I permit clients, who provide good answers to the three questions, to ask whether the project CAN be delivered by a particular deadline…I can answer that, when armed with good information. I do not any longer accept projects with fuzzy answers to the three questions, when the client has a date pre-specified. My professional reputation demands that I deliver quality software that satisfies the interests of all stakeholders. My duties to my fellow developers require that I not place their reputations at risk or put them into situations that force them to work 80-hour weeks. I will not risk being required to put in hundreds of hours that prove to be unbillable, thereby effectively reducing my earning power. I associate a terribly tiny probability with the outcome that the project will be a success under conditions that I can’t develop my specifications from good business requirements but am given a delivery date.

      I note that fuzziness of requirements WITHOUT a deadline is a very different case. If a customer needs help developing the answers to “What, How, and For Whom,” I can be retained to consult and assist with the determination of those answers. That, however, does not fit within the scope of this post.

      It’s like the old saw, “how long is a piece of string”? Without clearly stated “What, How, and For Whom,” I can’t say how long it will take or how much it will cost. I certainly can’t offer any reasonable guarantee of a delivery date. ‘Tis a harsh reality, but true (unless you’re a starving, young developer with no reputation to preserve and willing to risk getting a bad one early out of the gate…not recommended) – deadline before specs should be avoided like plague – it’s a ticking bomb.

      Do your best to help customers determine missing pieces. Be patient and gentle with the clients, since they may have a good but as yet unspoken grasp of the absent aspects or may be able with encouragement to formulate them. Bottom-line – if the customer can’t or won’t be convinced to create the necessary parts, they are likely expecting you to do their job for them. When such “projects” (VERY loose usage) come with a proposed deadline for delivery – don’t accept them. You won’t well serve your customer or yourself to cook up a disaster.

The “Deus in Machina” – Programmers as a New Priesthood

This idea isn’t original, but I was recently reminded of it. I couldn’t locate the article in which I first encountered this analogy in order to credit the sublimely funny author of the original (I ran across it in print decades ago…maybe not everything ever published in print is indexed by Google?!). So, I’m going to redevelop the notion here. It is my hope both to educate (in a project management kind of way) and amuse (stand a little further away, just in case the lightning strikes).

Primitive peoples had priesthoods, whether called “shamans,” “medicine men,” etc., who were charged to know the ritual secrets by which to appease the gods. Auguring by entrails wasn’t something just anybody could be trusted to do. Knowing which animal to sacrifice, under which phase of the moon, and in which hand had to hold the knife was arcane business, if the god was to be successfully appeased. Do it wrong, and you get a flood instead of the gentle rainfall needed to nurture your crops. Now, some minor secrets could be explained by the priesthood to the laity; small prayers and basic supplications were available to the regular folk. However, such practices needed to be prescribed by the cleric and followed to the letter without improvisation. Any failure of an attempt to propitiate the deity, whether by the religious professional or non-, was, of course, ascribed the sinfulness of the worshiper or to an imperfect performance of the ritual.

Is any of this sounding familiar…? This very model seems to be echoed in the modern practice of IT. There are supplicants (customers) who come to the priests (IT professionals) to perform the big rituals, like building entire systems and configuring databases. Many of these same worshipers demand of the priests that they provide detailed accounts of practices suitable to the laity, e.g., teach me how use the program or change rows in my table. The god, in this analogy, is some mysterious, powerful being ensconced within the otherwhere of the computer. This being has the marvelous power to fulfill requests, if appeased, and to wreak unspeakable havoc, if offended. This god can only be properly addressed by practices beyond the ken of the average person. Often, not even the priests fully comprehend the inner workings of the “mind” of the god in the machine. Certainly, no lay person can hope fully to grasp the mysteries.

In our contemporary world, IT professionals have adopted a role reminiscent of the primitive shaman. Our customers have little understanding of how we operate to make the machine answer their prayers. These same customers follow the instructions from us shaman types, regarding how to make their own attempts to convince the machine to fulfill their wishes.

Let’s try to demystify IT.

For ourselves, let’s gain deeper insights into how to convince the machine to serve the needs of our customers. This means gaining better understanding of hardware architectures, communications protocols, design principles, programming practices, etc. The more we know about the strengths and weaknesses of our tools, the better we can address the requirements of our clients’ projects.

For our customers, let’s try to provide better training that moves them out of the mindset of “ritual.” Let’s lead them into the light of better appreciation for how their actions affect and effect the satisfaction of their requests. Let’s give them a firmer but more flexible grasp of ways they can do things (gasp!) without our intercession. Let’s provide easier rituals in the form of simpler, more robust interfaces and better error-handling. Let’s teach them the virtues of disaster recovery and continuation of business preparations (floods happen – they don’t need to be catastrophic).

Most importantly, let’s remove the cloak of mysticism and make perfectly clear, that 99% of the time, when things go wrong, the user has not “sinned” – it’s our fault. The machine is just doing exactly what it was told to do by us…WE simply failed to perform OUR “rituals” correctly.

Web Time: Our Clock vs. the Client’s

As developers, we do not live on the same clock (or calendar even) as our customers. This is true for programmers outside the context of web-development as well, but is often alarmingly more obvious and painful for the web-developer. Two major themes obtain here – managing clients’ sensibilities and avoiding burnout.

Our customers are mostly regular people, working the 9-to-5 thing. They have deadlines and understand the notion of “urgency” as it relates to work, but often, their approach is (”a la” Kipling) “doin’ things rather-more-or-less.” We live in a microcosm that demands, not only we meet specifications according to schedules, but that we do so for a bunch of annoyingly differently programmed display platforms, i.e., web browsers, and often with almost zero tolerance for error. No, I’m not pretending that we work for NASA or Bristol-Myers Squibb, where lives are on the line, if we miscode a line, but our customers often feel that way about it. So, with the sense of urgency that clients have about our products, you’d expect them to supply content, review presentations, test forms, etc., in general do all the jobs we warned them they’d have to in order to meet “THE DEADLINE” in timely fashion. If you hold that expectation, you will be disappointed. Without careful management by YOU, the web-dev shop, your client will become THE bottleneck in your development process. This will put your schedule at risk, and the client WILL BLAME YOU. In the truest sense, you ARE at fault, since you should have managed them better.

Managing customers’ in the performance of their duties with respect to an IT project, especially web-development, must become an integral facet of your general project management methodology. The Agile guys get this to such an extent that clients are fundamental contributors who participate side-by-side with their geek counterparts. There are a few older project management schemes that “encourage” this ongoing demand for frequent even daily client participation, but many that don’t. Regardless of whether you adopt a formal “school” of project management, your practices must incorporate a recognition that regular, frequent input from the client is required. If you rely on the customer for the provision of actual content elements, this is critically more important. When it comes to testing beyond the unit level, customer efforts are vital from both a proving-correctness perspective and for usability assessment and feedback.

Clients don’t want your (their) project to miss deadlines, but rarely appreciate how they could cause that to happen. It must be one of your responsibilities to ensure that customers do grasp the importance of their roles in the process. Analyze your project time-lines to identify the must-have-by dates for client deliverables and actions. Reassess these frequently and keep the client informed. Detect schedule risks early and often, and share openly and directly any concerns you identify. Remember that the customer is busy, doing whatever it is constitutes their real business. This doesn’t excuse them from completing the tasks you require for your project, but does explain why the client may overlook or mis-assess the priority of those duties.

You have an additional responsibility to your developers. You must not allow the project schedule to become compromised in a manner that leads to a combination of dead-time followed by 60-hour work-weeks, or, for that matter, consistently 60-(or more)-hour work-weeks, period. I enjoy working whenever I want, but I purely telecommute. Evenings and weekends are fine, as long I am free to choose and manage my own time according to project demands. However, I do not enjoy “MUST WORK 30-HOUR WEEKEND” situations that devolve from an attempt to keep a deadline that’s at risk, because a client failed to meet a content delivery schedule. No (sane) developer enjoys that.

If you fail to keep your clients on track for deliveries of their parts, and don’t adjust schedules, you risk burning out your developers (even if that’s only yourself). You will generate anxiety and resentment and a lower quality of product. You will reduce morale and customer confidence.

Recognize and manage your customers as a part of your development team to the fullest extent possible. Make clear early and remind often of upcoming delivery targets. Accept that it is absolutely up to you to focus the clients’ awareness of the time-sensitive nature of their contributions to the project. Clients do not live on our clock and need our help “telling time” project-wise.

The Social Internet – Part Two: Social Bookmarking App

In Part One of this post, I focused more generally and less technically on issues related to marketing and SEO. One of my arguments was that the benefits of viral marketing could be WAY leveraged by adding a collection of links to your pages for the bookmarking services. By making it easy for visitors to “share” your site, the likelihood of being shared goes up. In this post, I explain the widget I developed for providing this functionality (top, right corner of this page). I had intended to offer that in the first post, but Matt(y-me-boyo) Trinder, who was kind enough to proof-read the original, pointed out that it was kind o’ too technical for the base topic. That is, bunches of normal (non-developer) people could get plenty of useful ideas without having to hurt their heads reading around the techno-bits. So, having been saved from “going over to the dark side” by Matt, I now offer the missing uber-geek presentation herein.

I took the approach of “widget-izing” the collection of icons/links as a JavaScript object that looks at the URL of the page in which it’s embedded and parses the URL into the parameters that each of the bookmarking sites expects when it receives a parameterized (GET) request. This makes it dead simple for visitors to bookmark the page (and e-mail…never neglect the mailto: pseudo-protocol) and simplifies my job when incorporating the sharing support during development.

The visitor needs only click an icon for a bookmarking site to which he (already) subscribes, enter his account credentials (probably “remembered” by his browser) with the service; the rest of the data is pre-loaded in the call to the service. This cuts the chances of the visitor mistyping the bits that matter to the client site or even being bothered to copy/paste any of that data. The collection of icons/links on this page gives an example of the implementation. Also, by widget-izing the process, I (as developer-guy) don’t have to edit the widget for every page to which it is included; I just put an inclusion target (a <div> element with an id) in the page markup and include the style and script blocks in the head of the page (valuable since I type slowly and often make miskates). The object that constitutes the widget is parameterized, so that you can customize it at the point you create an instance.

If you want to recycle the widget for your own ends, you need:

http://www.s8design.co.uk/css/viralLinking.css
http://www.s8design.co.uk/images/viralLinking/*.*
http://www.s8design.co.uk/js/viralLinking.js

The CSS and JS files need to be included to your HTML HEAD blocks from wherever you store them for your site. You also need to add a target container (the default is <div id=”_vlTarget_”></div>) in the body of your HTML.

The object definition of the ViralLinkManager can be modified to offer other (more, less, different) social bookmarking services as suits your taste. Just edit the vlLinksArray variable (should be relatively obvious how-to).

The only caveat is that, if your page already has an onload event handler, the function initVL() needs to be registered as well, and the declaration of the onload handler in the JS file needs to be disabled. Have fun viral-izing your sites!

The Social Internet – Part One: The Web as a Marketing and Promotions Tool

Increasingly, the Internet is becoming a flat(tish – not flat yet but getting flatter by the day) social community. We join on-line cultures such as Facebook and LinkedIn. We share bookmarks to sites we think are cool via services like Digg and StumbleUpon. We participate in on-line knowledge sharing groups, e.g., Yahoo!Answers, Google Groups. We Twitter about everything under the sun. For the business that owns an on-line presence, there exists great potential to leverage these on-line, social communities to generate heightened awareness in the wider universe of the Internet for potential customers of your business’ web-presence.

I won’t undertake an exhaustive listing of all the approaches that might be applied, but will give some illustrative examples of the general sorts of things that can succeed, if properly used. Let your imagine run wild.

First off, and most easily applied is the currently popular idiom of “sharing” a site with others. All that’s required is a non-intrusive but salient collection of links to the various social bookmarking sites and an “e-mail a friend” link. By placing a collection of links in the page, you raise the chances that visitors will share it. I prefer the icon idiom for links to these services; takes less room on the page and surfers recognize the logo icons of the various bookmarking services, even when the images are tiny (see top, right of this page). Part Two of this article will detail a widget I developed for this purpose (not the lightest weight fare for the non-technical reader). The main point is that there’s a huge opportunity to have your visitors engage in viral marketing of your websites and services. In order to maximize the effectiveness of this model, you have to make it EASY; some surfers will bookmark your site without your help, but more will do so, if you provide access to the services right on your pages. This puts your site in front of more potential customers and offers the additional virtue of SEO benefits from being widely linked from many other sites. Spiders love pages to which lots of other pages point.

If your shop (or your client’s) has a cause, even (especially!?!) if it’s just how deeply concerned you are to serve your customers and do business well, promote it on your site. Give it a blog (WordPress is WAY simple…you’re there now). If you (and your employees) have the dedication to update the commentary on a relatively regular (or at least frequent) basis, you can provide scads of content directly and simply. This creates more on-line content of interest to people who share the cause. Believe me, there are other standard-bearers for any cause you own; if only a few find your expressions worthy of cross-linking, you will kick your competitors tails SEO-wise. For general (not cross-linked) SEO value, this approach enhances and extends the volume of your content and keeps the change frequency higher; for spiders, “content is king.” as the saying goes. Frequent updates and increasing volume favorably impress search engines (especially appeasing the Google gods).

News items allow the chance to show currency in your grasp of the wider world as it pertains to your business. Providing links to important issues published elsewhere on the Internet can not only make you look savvier and more engaged, but gives surfers a motive to revisit your site and recommend it to others; that is, you pre-filtered pertinent, relevant content, removing the visitor/subscriber’s burden to search for it. Again, the nature of news is (definitively) frequently changing – fresh content for visitors, subscribers, and the spiders. Did I mention “better SEO”?

Join a community (or six) and participate (lots) in meaningfully contributory ways (NOT like, “sweet, me too” – express yourself, even [read "especially"] if it’s counter the popular trend or originally insightful, as long as it’s honest and represents your REAL business model and concerns). If you have expert employees, encourage (maybe even bribe ‘em with a point-system related to positive replies) them to do the same; you retain these folks because you value their skills – leverage that. You (and your employees) don’t need to advertise THE COMPANY by talking about it in every post (although a tasteful sig line can include a link to your home-page), but include your (business) home-page, a description of your services, and your values in your profile. The more useful your contributions to the community, the more likely people will be to poke around in your profile and discover your business (or explore the sig link, if you use one).

As promised, I won’t flog this horse to death (especially not in all its colors), but I hope this post will have sparked some new and useful ideas for you. Be careful to be REAL, i.e., offer valuable content, and easy tools – accurately assess and express your goals and commitment…take realistically chewable bites. Don’t place yourself in the situation of getting bookmarked or linked for the WRONG reasons. Don’t approach these resources cynically, and they can launch your site(s) in both direct, grassroots awareness of what you do and about what you care as well as SEO.

Javascript – To support or not to support

Contemporary web-development is founded increasingly on the “Web 2.0” vision of rich, interactive media. JavaScript provides an invaluable tool to enhance modern web pages and increase the sophistication of website interaction to rival and even surpass that of desktop applications.

The introduction of AJAX (Asynchronous JavaScript And XML) and its ability to provide new content and functionality to a website without the need to refresh the entire page has become the backbone of the “Web 2.0″ revolution. So much so that the majority of rich and interactive websites rely on JavaScript and in particular AJAX.

There are very few motives to disable JavaScript in light of modern browser capacities, and the number of people browsing with JavaScript disabled is dwindling (Fig 1). Modern browsers permit the regulation of JavaScript to address security issues and can be tuned to suit the needs and concerns of any user without disabling JavaScript completely.

Figure 1. Some recent statistics related to JavaScript enablement are:

Jan 2008 | Enabled: 95% | Disabled: 5%
Source: http://www.w3schools.com/browsers/browsers_stats.asp

Feb 2008 | Enabled: 93% | Disabled: 6%
Source: http://www.thecounter.com/stats/

Other media, such as Radio, Television and even Print, do not provide 100% coverage of all potential customers, and the same is true of the Internet. The use of JavaScript is not an accessibility issue that discriminates against users with disabilities, nor does it affect visitors based on any preconceived geographic, social, cultural, or ethnic criteria. There are a small percentage of web users who make a conscious decision to disable JavaScript and as a result do not benefit from this significant advancement in web technology.

It is possible to develop websites which maintain parallel content that does not rely on JavaScript; however, there are real costs to maintaining such a system. Server-side management can substitute dynamic behaviour to some extent, but there will be significant degradation of user experience and website performance. Such an approach cannot provide the same benefits or positive user experience as offered with JavaScript available.

Any entity considering the publication of web pages should determine the degree of its reliance on JavaScript in terms of expected Return On Investment (ROI). Some questions by which to assess potential ROI are:

  • Who constitutes the expected, potential customer base?
  • How likely are potential customers, who surf the web for candidate services in the categories we provide, to be among those who disable JavaScript?
  • What is the probability of a significant opportunity loss for a refusal to provide any/all content to a small fraction of visitors?
  • What is likelihood of a significant, negative impact on our brand for refusing to offer more than minimal support or possibly none to visitors without JavaScript?
  • How much will the parallel development of content cost?
  • What will be the additional costs and risks during development and ongoing support of alternative approaches to presentation?

With the answers to these questions in hand, a rational decision can be reached.

Opens in a new Window