My Web Development Coding Standards

Posted in Microcode on August 13th, 2011 by admin – Be the first to comment

So, I was thinking about the best practices I use in my own development, especially in regards to HTML/CSS/JS and this is what I came up with. Obviously there are as many ways of coding as there are developers (and probably more), but these are ones I’ve found which works for me.

Note I assume a certain level of competency here. I won’t bother with advice like “Never use the FONT tag”, “Never use inline styles” or “Avoid infinite loops” because I think that should be obvious.

HTML:

Use as few elements as you can.
Use the appropriate elements.
If you need the element to be on its own line, use a block element like p or div. If you need the element to flow with the text or be in the same line as other elements, use an inline element like span.
If you have a list of links, use a UL with LIs.
You can nest these if you have multiple levels of lists. A nested list should have the following structure:

<ul>
  <li><a href=”#”>List item in first level</a></li>
   <li><a href=”#”>Possible header for nested list</a>
    <ul>
      <li><a href=”#”>Nested list header</a></li>
    </ul>
  </li>
</ul>
Avoid using the <br/> element.
It is semantically meaningless and in almost all cases the appearance can be replicated with CSS.

CSS:

Definitions: (from)

Rule set:
The selector, curly braces and contained declarations.
Selector:
Everything before the left curly brace. Multiple selectors are combined with commas.
Declaration:
A single property/value line.

Naming conventions:

Never use the same name for both a class and a name.
This can get very confusing very fast. If there is a single element with id=”leftnav” class=”leftnav”, what does it mean to have another with id=”othernav” class=”leftnav”? One’s the “real” left navigation element, and the other is just kind of a left navigation element?
Names should be descriptive of the content contained, not the style given.

Bad Examples:

#leftnav {}
.underline {}

Good Examples:

#globalNavigation {}
.productList {}

Organization:

Rule sets should be added to the stylesheet in the following order (comments should delineate each section):
  1. Reset styles which affect HTML elements (e.g., a, ins, del)
  2. Classes which are used on all (or several) pages (e.g., .clear, .error)
  3. Classes and IDs which are used for widgets used on the header/footer/gutter or on several pages (e.g., .scrollable, .navigation a)
  4. Page-specific classes and IDs, and page-specific overrides of classes and elements used above (e.g., #categoryList .scrollable)

A note on websites with large numbers of rule sets.

Before adding a class, look to see if it’s already there. I’ve worked at places with no fewer than five classes which exist solely to clear floats.

Also, realize that multiple classes may be applied to an element. So, in the case of clearing floats, if you need something to have a "clear:both" declaration, and something else, you can add class=”clear something” and both styles will be applied. That said, don’t create a bunch of one-declaration rule sets and have fifteen classes on an element.

Other points of contention

There is a trade off between readability/maintainability and performance. I generally prefer the former to the latter. I think the tools are available to automatically minify/compress CSS and JS such that the authors shouldn’t worry about it.

One selector per line.

Bad Example:

#leftnav ul li,.leftnav,#egbdf,.iLikeLeftMargins{margin-right:11px;}

Better Example:

#leftnav ul li,
.leftnav,
#egbdf,
.iLikeLeftMargins {
  margin-right: 11px;
}
Even if multiple selectors share the same declarations, do not group them in the same rule set if they apply to different pages/widgets/elements.
While you’ll buy some performance gain, it is negligible compared to the maintenance risk.

Bad Example:

ins, .left_nav ul li a:hover, #header a:hover, #header_nav a, #someOtherPage .buttons span.link, #randomElement a, #main_wrapper .breadcrumb a, #idWhichOnlyOccursOnOnePage a{text-decoration:none}

Good Example:

Assuming the following global rule sets:

a,
a:link,
a:active,
a:visited {
  color: #000;
  text-decoration: none;
}
a:hover {
  text-decoration: underline;
}

This obviates the need for many of the selectors listed above.

/* Generic Styles */
ins {
  text-decoration: none;
}
…
/* Left navigation */
.ms_left_nav ul li a:hover {
  text-decoration: none;
}
…
/* Header */
#ms_header a:hover {
  text-decoration: none;
}
…
/* Product Details */
#dr_ProductDetails .pd_buttons span.pd_Link {
  text-decoration: none;
}
…
Always end every declaration with a semicolon.
This makes maintenance easier as you can add declarations without worrying about semicolons.
Avoid using the !important declaration.
It overrides the cascade and makes debugging CSS more difficult. If you’re finding a declaration is not being applied, try changing the selector’s specificity (e.g., add another level to the selector).

ECMAScript (a.k.a., JavaScript™, JScript™)

Naming conventions:

Be explicit in naming variables, methods, etc..
In addition to CSS, I also feel readability is paramount in ECMAScript as well. Thus, I will always name a variable “selectedMonth” rather than “m”. Again, minifiers/compressors should be able to help mitigate any issues with verbosity.
Prefer many shorter functions to one long one.
I might get in trouble for this one, since there are people who love those functions, but I follow the maxim that a function should do one thing well. For instance, I’ve seen an event handler which was approximately 1000 lines long, which itself made other event bindings. I find it much easier to understand if the binding of the event points to a single function, and that single function is broken up into concrete units of work. This factorization helps with testing and debugging.
Prefer a single object parameter to multiple simple type parameters
I only started doing this recently, but it makes refactoring a lot easier if I don’t have to change the signature of a method. Obviously that also obscures what required properties the object parameter must have, etc., but I still find it easier.
Don’t monkey with the built-in objects.
I know, it’s very tempting and makes coding a lot easier if you just, say, add a forEach method to the Array object if the browser doesn’t have one, but it makes debugging a PITA. How do I know if a bug I’m seeing is in the native implementation or some library’s override? I don’t, and that makes me a sad coder.

jQuery

Recently, I’ve been using a lot of jQuery, so this is a big topic for me.

Naming Conventions

Prefix variables which will hold the results of a jQuery selection with a dollar sign ($).
Since jQuery uses the lone dollar sign as its alias, this helps you remember you can use the jQuery methods on the object.

Coding Conventions

I’ve noticed a lot of code in the intrawebbers using jQuery almost exclusively with anonymous methods and the like. I’m not too keen on this trend, as it makes it somewhat difficult to debug and read. I prefer to used named functions and the like, which is not impossible to do with jQuery.

Cache the results of a selection!
This one gets the Bee in my Bonnet award for most annoying preventable performance hit. See the example below.
Use context
Where possible, use the overload of the jQuery method which takes a context, or use the find() method. Both are faster than using document as the context as is the default.

Examples for caching and context

Consider the following:

$('a').click(function () {
  if ($(this).parent().attr('id') == 'linky-poo') {
    $(this).addClass('linky-doo');
    $(this).parent().removeClass('linkage'));
    $(this).parent().find('a').filter('#' + $(this).attr('id')).css({'font-weight':'bold'});
    $('.expandme').each(function () {
      if ($(this).attr('class') == 'smushable') {
        $(this)[0].style.display = 'none';
        $('.linky-doo').attr('data-dohickey', $(this).attr('id'));
        $('.linky-doo').show();
        $('.linky-doo').css({'color':'#ff0000'});
      }
    });
  }
});

A made-up example, to be sure, but not far from what I’ve seen. So here’s how we can make it better:

  • Use this, if you can. In the event handler, this will refer to the current target of the event. Simple attribute queries and additions can be made without the overhead of jQuery, but, if you need it…
  • Cache $(this), if you need it many times. Every time $(this) is written, you’re asking jQuery to create another object. So, in the example above, a naive refactor would be:
    $('a').click(function () {
      var $me = $(this);
      if ($me.parent().attr('id') == 'linky-poo') {
        $me.addClass('linky-doo');
        $me.parent().removeClass('linkage');
        $me.parent().find('a').filter('#' + this.id).css({'font-weight':'bold'});
        $('.expandme').each(function () {
          var $expander = $(this);
          if ($expander.attr('class') == 'smushable') {
            this.style.display = 'none'; // or $expander.hide();
            $('.linky-doo').attr('data-dohickey', this.id);
            $('.linky-doo').show();
            $('.linky-doo').css({'color':'#ff0000'});
          }
        });
      }
    });
    
  • Cache other selectors and traversals. Again, each time you call a function, work is done, so if you can only do it once, why not cache the result? Another pass:
    $('a').click(function () {
      var $me = $(this), $myParent = $me.parent();
      if ($myParent.attr('id') == 'linky-poo') {
        $me.addClass('linky-doo');
        $myParent.removeClass('linkage');
        $myParent.find('a').filter('#' + this.id).css({'font-weight':'bold'});
        $('.expandme').each(function () {
          var $expander = $(this), $linkyDoo = $('.linky-doo');
          if ($expander.attr('class') == 'smushable') {
            this.style.display = 'none'; // or $expander.hide();
            $linkyDoo.attr('data-dohickey', this.id);
            $linkyDoo.show();
            $linkyDoo.css({'color':'#ff0000'});
          }
        });
      }
    });
    

I may add more as I am inspired and comments are made.

console.log for everyone, including IE8, IE9, Firefox, Chrome and possibly Safari!

Posted in Microcode on July 8th, 2011 by admin – Be the first to comment

So, I was trying to figure out a way of allow people to call console.log without worrying if console was defined (as occurs when Firebug’s Console panel is not enabled or F12 Developer Tools is not open in IE8+). First thing I tried was just a simple function call like the following:

var dr = {};
dr.log = function () {
  if ('console' in window) {
    window.console.log.apply(this, arguments);
  }
};

Worked find in Firefox, but not so much in IE, where I got the message, “Object doesn’t support property or method ‘apply’”. Frickin’ IE. Awesome.

Searching about with the BinGooHoo got me to this question on the excellent StackOverflow, which led me to the following article: Internet Explorer 9?s problematic console object.

In my current engagement, we’re using namespaces with JavaScript to isolate functionality from the global scope. So, I have a global ‘dr’ namespace. I wanted to add all of the functionality of the console object to that global object so instead of if ('console' in window) window.console.log('foo'); I could just write dr.log('foo'); and not worry whether window.console was defined for not. Here’s what I came up with, borrowing heavily from the above article, and the linked articles on MDN for polyfills. The only problem I’m having right now is dr.log(‘log’) outputs the following in Chrome:

Not sure why that’s happening, but for now it’s Good Enough™.

// Array.prototype.forEach polyfill
if (!Array.prototype.forEach)
{
  Array.prototype.forEach = function(fun /*, thisArg */) {
    if (this === void 0 || this === null) {
      throw new TypeError();
    }

    var t = Object(this),
      len = t.length &gt;&gt;&gt; 0,
      thisp = arguments[1],
      i = 0;
    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    for (; i &lt; len; i++) {
      if (i in t) {
        fun.call(thisp, t[i], i, t);
      }
    }
  }; //Array.prototype.forEach
} //if (!Array.prototype.forEach)

// Function.prototype.bind polyfill
if (!Function.prototype.bind) {
  Function.prototype.bind = function( obj ) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5 internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var slice = [].slice,
      args = slice.call(arguments, 1),
      self = this,
      nop = function () {},
      bound = function () {
        return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments)));
      };

    bound.prototype = this.prototype;
    return bound;
  }; //Function.prototype.bind
} //if (!Function.prototype.bind)

dr.debugMethods = ['log','debug','info','warn','error','assert','clear','dir','dirxml','trace','group','groupCollapsed','groupEnd','time','timeEnd','profile','profileEnd','count','exception','table'];

// Add methods of console to dr for easier typing
if (Function.prototype.bind && console) {
  try {
    dr.debugMethods.forEach(function (method) {
      dr[method] = this.call(console[method], console);
    }, Function.prototype.bind);
  } catch (e) {
    if (e.message === "Function.prototype.bind - what is trying to be bound is not callable") {
      dr.debugMethods.forEach(function (method) {
        dr[method] = Function.prototype.call.bind(console[method], console);
      });
    }
  }
} else {
  dr.debugMethods.forEach(function (method) {
    dr[method] = function () { };
  });
}

My del.icio.us bookmarks for February 22nd

Posted in LinkDump on February 22nd, 2011 by mike – Comments Off

links for February 22nd:

IE9 Beta noscript oddity

Posted in Geekdom, Microcode on February 7th, 2011 by mike – Be the first to comment

While working on an e-commerce site, I ran across an interesting bug in the IE9 beta.

Disable JavaScript via the following path:
[Gear], Internet 0ptions, Security [tab], Custom level…, Scripting, Active scripting, Disable.

Next, open a page with the noscript tag in it and has a valid DOCTYPE to trigger strict mode, like, say this one.

Note that the text in the noscript displays as plain text, not as the HTML as one would expect. Granted, the example posted is not exciting—you see a p tag—but in reality it can really screw up your life.

Adding a bug to Connect soon… and I would include a direct link, but it doesn’t seem to be supported. Feedback ID is 641747.

Obviously the fix is to display the site as you want without script enabled, then use script to make it look like you want with script enabled. Basic “progressive enhancement”. But sometimes, especially in crunch time when the site supposed to be going live in a few weeks, you don’t want to reengineer your site…

My del.icio.us bookmarks for January 21st

Posted in LinkDump on January 21st, 2011 by mike – Comments Off

links for January 21st:

My del.icio.us bookmarks for October 5th

Posted in LinkDump on October 5th, 2010 by mike – Comments Off

links for October 5th:

My del.icio.us bookmarks for October 1st

Posted in LinkDump on October 1st, 2010 by mike – Comments Off

links for October 1st:

My del.icio.us bookmarks for September 26th

Posted in LinkDump on September 26th, 2010 by mike – Comments Off

links for September 26th:

  • Catskill Mountain Moccasins – The finest Custom Made Moccasins from Buffalo and Bull Hide Leathers made from a cast of your feet and legs

My del.icio.us bookmarks for September 21st

Posted in LinkDump on September 22nd, 2010 by mike – Comments Off

links for September 21st:

My del.icio.us bookmarks for September 21st

Posted in LinkDump on September 21st, 2010 by mike – Comments Off

links for September 21st: