Category Archive for 'web'

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!

Facebook connecting the dots?

An NY Times Op-Ed piece by Eduardo Porter about web privacy finishes with the following:

But with more and more information about people’s credit cards, browsing histories and identities sloshing around online, I wonder whether this will do. A few months ago, I nervously created my first Facebook page with the minimum necessary information to view pictures posted by old friends.

I returned to the page a few days later to discover that somehow it had found out both the name of my college and my graduation class, displaying them under my name. I have not returned since. In the back of my mind, I fear a 28-year-old hacker and a couple of Russians have gathered two more facts about me that I would rather they didn’t have. And it’s way too late to take my life offline.

Really? Facebook is connecting the dots this way?

Hard to make a true determination of what he means. His Facebook profile is obviously accessible to friends only. It could be that Facebook connected the dots and presented them to him for confirmation. That would certainly be less insidious than making the connections and imposing them upon his account. For example, he could easily wish to keep his Facebook profile clear of various episodes of his past life, like college, previous employers, etc.

But it surely shows that every little bit of ourselves that we leak out into the cyberspace represents another potential hook that a data miner could use to link vast data repositories.

One has to wonder if there is really any privacy left at all. We get by on obscurity, the (blind!) hope that no one will look too closely. But I wonder how most of us, with modest connections to to electronic world – an email address, some credit cards, a few online purchases, perhaps even a Facebook account – would fare if someone with access to those data mines turned their attention on them. In fact, it’s probably the case that the data miners do this themselves via automated searches on their data stores.

As Mr. Porter said, way too late to pull our lives offline.

No canonical domain on NYTimes.com

I am surprised to find that the NYTimes.com does not provide a canonical domain for its homepage or for its articles (at least, for the small sampling I checked). That is, I get the “exact” same behavior in my browser irrespective of entering http://nytimes.com or http://www.nytimes.com.

There is no shortage of opinion about whether to use a www or no www on your domain. Nearly all agree that your site should respond to both versions.

Read the rest of this entry »

GoDaddySucks.com

I don’t really hate GoDaddy.

I do confess that I don’t like them all that much. For the supposed leader – at the least, one of the most recognizable names – in domain registration, I find the experience of dealing with them pretty bad: bloated admin pages, opaque admin interfaces, interminable payment processes.

I even got bitten by one client who was using them for Windows hosting, but the account didn’t support PHP. What basic hosting account these days doesn’t support PHP? Goodness!

Still, I can usually get done what I want, though in a clearly sub-optimal way. Like I said, I don’t really hate them, at least not with the white hot intensity of a thousand suns, a level of fury that comes easily to me when the topic turns to IE6.

So, I was surprised to find that the domain name godaddysucks.com redirects to the godaddy.com home page. A whois check shows that GoDaddy themselves have the domain name.

A bit of pro-active defense there, a good lesson for all of us.

[ As a side note, GoDaddy was not so pro-active as to secure certain hyphenated variants of the godaddysucks.com theme, some of which lead into a distinctly "red-light" area of the web. 'Nuff said. ]