Archive for 'September, 2009'

HTML email templates from CampaignMonitor: Fail?

Clients love HTML email.

Done correctly, it looks slick as all get-out; it prompts users to action; it drives traffic for a special promotion; presents an exciting, professional image; lifts you aloft and floats you to heaven. All with higher response/action rates than plain-text email messages.

However, as every web developer knows, doing it well is a nightmare. Design/layout is the easy part; the sticky parts are numerous. Different email clients render HTML email with, shall we say, somewhat uneven support for web standards that are increasingly respected in modern browsers. Further, many email clients come configured with default settings to that disable images, adding another factor to consider. Finally – well, not finally, but the list of issues feels effectively endless – HTML email is often used by spammers, so there are more complicated considerations associated to ensuring that your messages do not get incorrectly tagged as spam.

There is a growing body of best-practices that has slowly developed for HTML email. These practices are not “best” in the sense that they represent elegant, flexible coding philosophies (like DRY, OO, for example) or minimal load times or optimized development practices. Rather, these ideas are considered best-practices, IMHO, merely in the sense that they “work”: they offer the best chance that your message will be received by the intended recipient and be reasonably well-rendered when he views it.

These best-practices include foregoing all the techniques we learned for creating semantic markup that cleanly separates content from presentation using CSS; instead, we are told to use tables for layout. We should no longer refer to styles in an external style sheet since most email clients – especially web-based ones like Hotmail, Yahoo, and Gmail – will strip them out; rather, we should use inline styling, repeating style information on nearly every element that needs it, inducing bloat and making modifications a tedious search-and-replace activity rather than a simple change in a single style declaration.

Other best-practice resources often conclude by pointing to Campaign Monitor or MailChimp and advising readers to download their free templates and use them as directly or as a starting point for editing or even as a guide to these best-practices. Both sites claim that their templates have been tested to render fine in all major clients.

Now, Campaign Monitor is great. These guys are founders of the Email Standards Project. I totally support the idea that someone should be pushing email clients towards better support of web standards, especially CSS support. The first step in that direction is measuring and evaluating the current support. And their chart of CSS support in major mail clients is a tremendous resource.

But the first template I downloaded from CampaignMonitor violates a bunch of these best practices right off the bat and fails to render correctly in Gmail. The template has nearly all of its styling inside a <style> tag inside the page’s <head> section. CampaignMonitor’s own CSS support guide referenced above notes that such an approach will not work with Gmail, yet their template includes it and claims to render fine.

Gotta tell ya, I’m a bit disappointed.

Refactoring Video Renderers with Design Patterns and Autoloaders

On the face of it, it’s a very simple request from a customer.

We have a page listing our YouTube-hosted videos. Each video has a thumb and some descriptive information, all linked to a page that renders the descriptive info and the YouTube embed codes so the visitor can view the video in our site wrap. Customer wants to add a new video to the list.

Simple. Should be nothing. Piece of cake.

But it turns out that existing rendering/embedding code was set up to expect videos with only a YouTube embedding. The new video is hosted at another site which does their embeds in slightly different way. And there is every reason to think that the next video that comes up will be different still.

Further, the supporting code for summary and detail renderings (summary rendering: display a thumb, some video metadata, and links to play, download, etc; detail rendering: display the actual embed from the video provider, some video metadata, links to download, etc) was not as well structured as I would have liked. Although there was a summary rendering class and a detail rendering class and both descended from a common base class to share some common functionality, the commonality was all based on the YouTube embedding. Also, the caller instantiated the renderers directly using the new operator, rather than using a factory design pattern.

So, what it seems was needed is something that puts all the commonality (title, speaker, place, date, thumbnail, general layout of the summary pages and the detail page) in a single place; allows enough flexibility to deal with embeddings from various sources; and uses established design patterns for easy use and maintenance.

So, I refactored all our code into a more modern approach that uses a factory pattern to create renderers that are capable of dealing with the type of video embed required. Start with a parent class for renderers Customer_Video_Renderer containing much of the functionality that would be common across various renderers and video embedding types. In particular, it defines the primary interface for using the renderers:


class Customer_Video_Renderer 
{

	public function renderSummary()
	{
		// to implement
	}
	
	public function renderDetail()
	{
		// to implement
	}
	
	// other supporting code common to renderers
}

A generalized renderer for an embedded video now uses dependency injection as follows:


class Customer_Video_Renderer_Embed extends Customer_Video_Renderer
{
	protected $_embedClassName;
	
	public function __construct($video, $embedClassName = '')
	{
		parent::__construct($video);
		$this->_embedClassName = $embedClassName;
	}
}

The variable $embedClassName variable contains the name of a class that must support the static function getEmbedCode($video). So for example:


class Customer_Video_Renderer_Embed_YouTube 
{
	public static function getEmbedCode($video)
	{

		$w = $video['speech_video_width'];
		$h = $video['speech_video_height'];
		$u = self::_getEmbedUrl($video);

		return <<< EOT

		<object width="$w" height="$h">
			<param name="movie" value="$u"></param>
			<param name="allowFullScreen" value="true"></param>
			<param name="allowscriptaccess" value="always"></param>
			<embed 
				src="$u" 
				type="application/x-shockwave-flash" 
				allowscriptaccess="always" 
				allowfullscreen="true" 
				width="$w" 
				height="$h">
			</embed>
		</object>		
EOT;

	}

	protected static function _getEmbedUrl($video)
	{
		return 'http://www.youtube.com/v/'.$video['speech_embed_code'].'&hl=en&fs=1';
	}
}

Then we use a factory to create renderers:


class Customer_Video_Renderer_Factory 
{

	public function create(array $video)
	{
	
		if (!isset($video['vType'])){ 
			throw new Customer_Video_Renderer_Exception('Video does not specify video type');
		}
		
		switch ($video['vType']) {
		    case 'youtube':
		        $renderer = new Customer_Video_Renderer_Embed($video, 'Customer_Video_Renderer_Embed_YouTube');
		        break;
		    case 'moneywatch':
		        $renderer = new Customer_Video_Renderer_Embed($video, 'Customer_Video_Renderer_Embed_MoneyWatch');
		        break;
		    case 'inline':
		        $renderer = new Customer_Video_Renderer_Embed($video, 'Customer_Video_Renderer_Embed_Inline');
		        break;
		    default:
				throw new Customer_Video_Renderer_Exception('Video specifies unsupported video type: '.$video['vType']);
		        break;
		}
		
		return $renderer;
	}
}

So the caller simply renders a video as follows:


// given a $video
echo Customer_Video_Renderer_Factory::create($video)->renderDetail();
	

And I am – finally! – using a standard __autoload function so all those irritating requires statements are no longer, well, required:


function __autoload($className){
    include_once str_replace('_', '/', $className) . '.php';
}

Can’t believe how smoothly it all went, how beautiful the code is now structured (though I see that there could be different ways of approaching it), and how easy it will be to add new video providers. Might even add unit-tests if I can find the time.

So pleased.

Update 2009-11-07: I realize now that the use of static methods was kind of a n00bish idea, that considerations of unit testing and loose-coupling should have dictated a more compositional approach, perhaps invoking one of the standard design patterns that applies. All I can say is that I’m moving that way, slowly but surely. Onward!

Zend Framework – Here I Come

Time to elevate my game.

After years of developing and tuning my own PHP-based web development framework which I have used on countless projects, I have decided to move into one of the more established PHP-based web frameworks.

My own framework is a loose collection of classes and methodologies that have worked pretty well so far. I can usually figure out how to do anything that has come up. Although it is a huge step up from so much of the the script-kiddie crap that is still fairly common – among even some successful commercial houses here in Phuket – I must confess that it never felt quite tight enough for me. It never lent itself to the kind of controlled development process I would ultimately like to be doing: source control, automated unit-testing, automated builds, and automated deployments.

There is no shortage of discussion out there about web frameworks: which ones are essentially CMS’s or mere libraries rather than full frameworks; which ones are tightly/loosely coupled; which ones are sufficiently true to established design patterns, to object-oriented principles, to MVC principles, etc; which ones are performance dogs, etc. I’ve read through much of it.

Upshot: I’m sticking with PHP, going with Zend Framework.

I’ve got nothing against the other PHP frameworks. CodeIgniter seems very approachable and has a decent community. CakePHP seems to have a lot of advocates and supportive community. Kohana, too, seems nice. Of course, there are many others.

And if I were really going to go wild, I would leap in Ruby on Rails about which I have never heard a single bad thing. But a leap into a new framework is enough without having to bite off the syntax of another language to boot.

Perhaps some other time I’ll get into all the reasons and do a comparative analysis, though it is just as likely that it will never happen since there are already tons of such resources out there and doing my own comparative analysis at a level that would be satisfactory to me would require becoming expert at all the others.

First step is to use a few of the Zend Framework classes here and there in a few projects, availing myself of the “loosely-coupled, use-at-will” nature of the library. Mostly to familiarize myself with some of the design patterns and to learn what supportive functionality is available outside the context of the full framework stack.

Eventually, I will commit to using the full MVC stack on a green-field project, either a brand new site or a redesign of an existing site. I already have one in mind. Both excited and terrified at the same time.

Go, go, go, …