Tag: web development

05
Mar

Soapbox: Native vs Web-Based Applications

As you’re probably aware, I develop mainly for the web. I love developing Web Applications – the technologies are great, it’s easy to use a blend of technologies, deployment is simple and they can provide a fantastic user experience. However, I also do quite a bit of native development in Objective-C and Cocoa, which I also love – the applications are quick, they fit in to your OS environment, and you can take advantage of really low-level APIs for threading etc. There are hundreds of debates on the web where web developers and native developers try and convince each other that their technique is best: this isn’t one of those debates.

This post was inspired by a talk at devnest this past Tuesday, where someone gave a presentation on developing mobile applications with jQuery Mobile. It was very interesting – I think jQuery Mobile is a fantastic framework, and it really simplifies the process of turning your web application into something that people can use on-the-go with their mobile devices. However, this person then introduced a piece of software called PhoneGap, which allows you to take an application you’ve developed in HTML/CSS/JS, offers you access to the low-level APIs, and lets you deploy it across multiple platforms as a native application.

Don’t get me wrong, jQuery Mobile looks great and works really well – but put it alongside a native application on an iPhone, for instance, and suddenly you see that the jQuery Mobile app actually is slow as a pig and looks out-of-place. That’s the sort of user experience I’d expect from a web app, but I’d expect a load more from a native application, especially if I’d paid money for it.

At work, I’ve been doing a load of research into different technologies and how we could utilise them in our roadmap. One thing I’m continually pushing for is using the best tool for the job. If it turns out that PHP is the best solution, great, but if it turns out that Python is the best solution, and you don’t know Python, you better get hold of some manuals and start learning. If you want to develop a mobile application, the device’s native language is the best solution. If you want to deploy across multiple platforms, and don’t need access to the device’s APIs, then develop a web app. If you do need access to the APIs, you’ve got a lot of work to do.

21
Nov

Words are funny, right?

Today I’ve hacked together and launched my own Twitter-bot, @chinesetwispers. The basic premise is that it finds tweets with certain words in them, replaces those words for other words which either sound like the word or are generally hilarious replacements, and then retweets it at the original author. I’m looking forward to seeing what it comes out with – hopefully no-one will get too offended!

As well as that, I’ve done some work on Twipestry, so it’s now a load more stable and produces more relevant results. As well as that it now uses the search API, meaning instead of just searching for users you can also do keyword-based searches as well. Lovely, no?

So that’s what I’ve been up to today. Other than that, I’ve been doing some work on DoodleDesk, trying to get it ready for release sometime soon, and also been working on Fretless on and off. Hopefully I’ll find a weekend or two in the near future to get both of these ready for a proper release. We’ll see…

31
Oct

Using CakePHP’s finderQuery Attribute For Complex Associations

I had some fun (“fun”) on a project the other day when I had to write a rather complex has-and-belongs-to-many association for a model in CakePHP. The basic scenario was this:

  • There are ‘Meetings’, which are associated with many People (and many People can be associated with many Meetings, but that’s not important here)
  • Each meeting has many ‘Conversations’, which currently are assumed to involve everyone in the Meeting

My task was to alter this model so as to cater for Conversations that only involve a subset of the People involved in the Meeting. For backwards compatibility, and to save on space (although admittedly the join table wouldn’t have exactly been huge), we decided to go with the following model:

  • We would create a ‘ConversationPerson’ model, which would obviously store the people involved in a conversation, but…
  • If a Conversation has no records in the join table, then the People involved in the Conversation is assumed to be all the people in the Meeting.

(Does that make sense?)

This is a (relatively) easy query to construct, so we decided to use a single query to define the association and then use the finderQuery parameter to tell Cake how to get the data. Our Conversation model then looked a bit like this:

<?php
class Conversation extends AppModel {
	...
	$hasAndBelongsToMany = array(
		'Person' => array(
			'finderQuery' =>
				'SELECT `ConversationPerson`.`id` AS `conversation_id`, 
						`Person`.* 
				 FROM 	`people` AS `Person`, 
						`meeting_people` AS `MeetingPerson`, 
						// Left join conversations with conversation_person
						// so we don't lose any conversations if there are 
						// no rows in conversation_people, and so we don't
						// get extra rows if there are
						`conversations` AS `Conversation` 
						LEFT JOIN 
						`conversation_people` AS `ConversationPerson` 
						ON 
						`Conversation`.`id` = `ConversationPerson`.`conversation_id`,
						// Count the number of associations in the
						// conversation_people table
						(SELECT COUNT(*) AS count 
						FROM `conversation_people` AS `CountConversationPeople` 
						WHERE `CountConversationPeople`.`conversation_id` = {$__cakeID__$}) 
						AS `Count`
						// This mimics the operation of an
						// if(count == 0){...}else{...}
						// If there are no associations in the conversation_person
						// table, grab the people from the meeting_person table
				 WHERE (`Count`.`count` = 0 AND 
						`Conversation`.`id` = {$__cakeID__$} AND 
						`Person`.`id` = `MeetingPerson`.`person_id` AND 
						`Conversation`.`meeting_id` = `MeetingPerson`.`meeting_id`)
						// If there are associations in the conversation_person
						// table, use those to define the people in the conversation
					OR (`Count`.`count` > 0 AND 
						`Conversation`.`id` = {$__cakeID__$} AND 
						`MeetingPerson`.`meeting_id` = `Conversation`.`meeting_id` AND 
						`MeetingPerson`.`person_id` = `ConversationPerson`.`person_id` AND 
						`ConversationPerson`.`person_id` = `Person`.`id`)'
		)
	);	
	...
}
?>	

This seemed alright, but Cake was throwing me error after error, and it took me a while to figure out what was going on. It turns out that when you perform a HABTM find in Cake, it expects to always see a join table. This is especially apparent when you select a group of rows, since it then uses the values in the join table to determine which row is associated with which model.

In the example above, Cake was expecting to always see two fields, one called ConversationPerson.conversation_id and another called ConversationPerson.person_id. Obviously, in the cases where the association exists in the join table, this is fine. However, no associations exist and we grab the data from the MeetingPerson table, Cake is unhappy. Unfortunately, Cake isn’t clever enough to look for those ids (conversation_id and person_id) in the other fields it returns, it explicitly wants them to come from a table called ConversationPeople.

Obviously, the solution is to use the query we created above to construct the join table, and then select from that. It is a bit frustrating that there isn’t a neater solution to this, but there we go. So, our Conversation model looked like this:

<?php
class Conversation extends AppModel {
	...
	$hasAndBelongsToMany = array(
		'Person' => array(
			'finderQuery' =>
				'SELECT `Person`.*, `ConversationPerson`.*
				FROM `people` AS `Person`,
					(SELECT `ConversationPerson`.`id` AS `conversation_id`, 
							`Person`.* 
					 FROM 	`people` AS `Person`, 
							`meeting_people` AS `MeetingPerson`, 
							`conversations` AS `Conversation` 
							LEFT JOIN 
							`conversation_people` AS `ConversationPerson` 
							ON 
							`Conversation`.`id` = `ConversationPerson`.`conversation_id`,
							(SELECT COUNT(*) AS count 
							FROM `conversation_people` AS `CountConversationPeople` 
							WHERE 
							`CountConversationPeople`.`conversation_id` = {$__cakeID__$}) 
							AS `Count`
					 WHERE (`Count`.`count` = 0 AND 
							`Conversation`.`id` = {$__cakeID__$} AND 
							`Person`.`id` = `MeetingPerson`.`person_id` AND 
							`Conversation`.`meeting_id` = `MeetingPerson`.`meeting_id`)
						OR (`Count`.`count` > 0 AND 
							`Conversation`.`id` = {$__cakeID__$} AND 
							`MeetingPerson`.`meeting_id` = `Conversation`.`meeting_id` AND 
							`MeetingPerson`.`person_id` = `ConversationPerson`.`person_id` 
							AND `ConversationPerson`.`person_id` = `Person`.`id`))
					AS `ConversationUser`
				WHERE `Person`.`id` = `ConversationUser`.`person_id`'
		)
	);	
	...
}
?>

In retrospect, I should have just bitten the bullet and populated the ConversationPerson table with the values from MeetingPerson (or perhaps gone one step further and inferred the people in the meeting from the people involved in Conversations in that meeting, but whatever), but in this case I think this was probably the nicest solution.

The example in this post is so incredibly edge-case that it will probably help absolutely no-one, but I thought I’d put it up anyway, since the Cake docs don’t mention requiring those particular fields when specifying a finderQuery.

24
Oct

An Interesting IE6 Bug (bleurgh)

I came across an interesting bug in IE6 the other day, and couldn’t find any documentation of it on the internet, so thought I’d share it with you all here (aren’t you lucky?).

I was working on a distributable widget, which has the functionality to grab some embed code so you can place it with pride on your own website. This embed code was generated dynamically by JavaScript based on some parameters the user entered, and was then placed in a textfield using the jQuery $().val(value) function. This worked fine in most browsers, but IE6 would throw a wobbly at this point in the form of an “Unspecified Error”. Incredibly helpful.

I found that the bug didn’t occur if I escape()‘d the value before I passed it into the textfield. It seems, therefore, that IE6 has an issue with strings that contain HTML content – presumably it was trying to parse the HTML when it was put in the textfield. The same behaviour was observed when using document.getElementById(…).innerHTML = value; as well.

The solution was to use the jQuery function $().text() – and this works cross browser. Presumably this only works for textfields – if you are setting the contents of normal text inputs then I’m not quite sure what you will observe. But then, you never are with IE6…

25
Aug

Setting up Snow Leopard for Web Development

My trusty old 1st-gen MacBook Pro died on me last week, so I’ve got myself a shiny new one, which is exciting! One thing I was looking forward to was a clean install of the OS, so I could re-appraise the way I used my computer. One of the things I decided to do was to move away from using XAMPP and have a more traditional set up using the built-in Web Sharing. Here, I’m going to talk about what I’ve done and how I propose to use my new laptop for Web Development to smooth my workflow.

Apache and PHP

Mac OS X Snow Leopard comes with Apache and PHP, although PHP is disabled by default. I didn’t know this to begin with, so I started off by installing Marc Liyanage’s PHP bundle. However, after installing this I found that I was getting 301 “Permanently Moved” errors on all my pages, so that was soon uninstalled.

To enable PHP on Snow Leopard, you need to open the config file in your favourite text editor (mine’s TextMate, but you can use vim, nano, or any other). In a terminal, open the file for editing (replacing ‘mate’ with the command for your text editor) entering your password when prompted.
sudo mate /etc/apache2/httpd.conf
You’re looking for a line like this:
#LoadModule php5_module        libexec/apache2/libphp5.so
If it exists, remove the # symbol, otherwise add the line in, minus the #. Save the file and exit the editor. Now you need to restart the Apache server, so type the following in the terminal:
sudo apachectl restart
You can test whether it’s worked by creating a file in your Sites directory that looks like this:
<?php phpinfo(); ?>
Call this file info.php, and then in your browser navigate to http://localhost/~yourusername/info.php – if it’s worked then you should see a nice table which has all the details of the PHP installation.

MySQL

If, like me, you’re going to be using MySQL for the database side of your web applications, then you’re in luck! It’s really easy to install, since MySQL provide some lovely .dmgs. Go to http://dev.mysql.com/downloads/mysql/ and choose the DMG archive most appropriate for you (remember to check your operating system version, and whether your computer is 32 or 64 bit). Note that all of these downloads are for Intel-based Macs only. When you’ve got the file, open it up and you’ll see 4 files. Start by installing the main MySQL application which will be called something like mysql-5.1.50-osx10.6-x86_64.pkg. When that’s done, I installed the MySQLStartupItem.pkg and the MySQL.prefPane files (both done by double clicking on them), which starts the MySQL server when I login and lets me control it through the System Preferences application.

You can manage the database in a number of ways, but I choose to use SequelPro. It’s a free application that’s got all the features you need in a lovely Cocoa-based UI. If you prefer, you could install phpMyAdmin or one of a number of alternatives, but I haven’t tried those so I shan’t give you any advice on them.

Starting Development

Now you’ve got all the components set up, it’s time to create some web apps! All the code will go in the Sites folder that’s located in your home directory. I’m going to be following Remy Sharp’s guide, which sets up domain names that point to your local machine (so, for example, I could develop and view on my local machine at the url http://imaginaryroots.dev). There’s quite a lot of work involved in that, so I intend to write a shell script to do the majority for me, but I haven’t gotten around to it yet…

Now all’s that’s left is to knuckle down and write some code – and let’s face it, isn’t that why we’re all here?

03
May

On Apple, Adobe and Flash

I’ve been interested today to try and catch up on the whole Apple / Adobe debate regarding Flash, specifically Steve Jobs’ open letter and the WSJ interview with Shantanu Narayen. Let me first get my opinions out the way: people who know me will know that I’m an Apple geek, but I’m also a Web Developer with lots of experience using Adobe products, Flash in particular. For a long while, I really disliked developing in Flash, until I discovered the MC Tween library (now Tweener), which finally let me develop in Flash the way I wanted to. But until this week, when Flash Player 10.1 Gala came out, my experience with Flash in-browser was, as it is for many Mac users (and still is for some), frustrating at best.

With the capabilities of fantastic JavaScript libraries such as Raphael, jQuery, MooTools and the like, not to mention the superb frameworks like Cappuccino, and the enhancements that are being realised through HTML5 and CSS3, I can’t help but think that Flash has had its time. I can’t help but think that for the majority of applications, Flash isn’t really an option anymore. Once there’s (hopefully) a widespread, standard adoption of the HTML5 and CSS3 specifications, it should be significantly easier to develop websites with the same aesthetic flair as Flash sites in these languages – let alone a lot more accessible.

I, personally, don’t miss Flash when I’m using my iPhone. If/when I get an iPad, I can’t imagine I’ll miss it all that much on there either.

Maybe it’s time for Flash to step down. What I would absolutely love to see is an application that has the same power as the Flash IDE with regards to creating animations, adding functionality etc, but that outputs in standards compliant HTML/CSS with a JavaScript library. Adobe are probably a bit too stubborn to admit defeat and produce this product, but something like this could be really awesome.

Jobs vs Narayen

Back to the debate. Is it just me, or are there some mixed messages going on here? Jobs talks a lot about Flash being a closed system, and that Apple are supporting the open community by placing the emphasis on HTML5 and H.264. Narayen then counters that by saying that the iPhone is a closed system, and that they are supporting an open system by creating authoring tools with single-click deployment to a wide number of platforms.

They’re all good points, and all correct. Although the specification for Flash is open (apparently, I didn’t actually know that it was until I heard it from Narayen today), it is still controlled mainly by Adobe since they have the monopoly on the actual Flash player. Jobs 1 – Narayen 0. The iPhone is very similar, in that the code and frameworks are available for everyone to use, but the actual platform is controlled by a single entity. Jobs 1 – Narayen 1. Apple are indeed supporting the open community, I think HTML5 and H.264 are definitely the right way forward, particularly on mobile devices like the iPhone. Jobs 2 – Narayen 1. Adobe are indeed working to create authoring tools with single-click deployment to the web on a large number of devices. Jobs 2 – Narayen 2.

Looks like a tie, right?

Thing is, I can’t help but think that Adobe are fighting a pretty pointless fight with their “single-click cross platform deployment” – what’s wrong with HTML? As far as I’m aware, every mobile device with any market share supports HTML, along with every computer connected to the internet. That seems pretty cross platform to me.

I’m completely with Jobs on this one. Yes, I am an Apple geek, and people will say “well, of course you’re going to side with Apple”, but I really think Adobe are barking up the wrong tree here. Flash is all but dead, Adobe should move on.

11
Feb

On Portability and Web Development

A friend linked me to this article this morning, and I think it’s worth a read. I’ve never given Google’s App Engine much of a look, largely because I’ve never gotten around the idea of compiled code running web apps (for some reason interpreted languages just feel right, but then that’s what I’m used to, and this is a post for another day anyway…). But there is something very interesting in that article, and that’s the portability of App Engine applications that would be obtained by having a number of cloud providers running AppScale.

In my time as a web developer I’ve done more than my fair share of server migrations, and each one has been horrible. It’s never an easy task, always fraught with issues, and almost always results in some amount of downtime (partly due to DNS switchover, but often a result of improper config on the new server as well).

Those sites were largely PHP, and only a handful were running Cake (which does make some things easier, but introduces other headaches as well). I’ve yet to do a server migration using Rails, but I can imagine it is a bit easier thanks to gems, capistrano and the like. But I’m sure the multitude of server configurations required – Apache, MySQL, email servers etc – mean that it’s never as easy as it possibly could be.

Wouldn’t it be great if we could abstract all of this? Wouldn’t it be great if I could open an account on a cloud provider, put its details in Capistrano (or whatever), click go and have my app running there instantly. I’m sure there are ways and providers that will do that for you. I’ve not looked incredibly deeply, but Engine Yard might do this, and it doesn’t look particularly cheap (not compared to, say a SliceHost VPS or the MediaTemple GS, both of which I run). It’d be awesome if there were the free quotas that App Engine offers, so that people could get into deploying real web apps without the hassle of manually configuring cheap servers or the cost of affording the top range hosts. Does anyone know of anything that does this?

28
Aug

Coda

You may know that I’m a Mac user, and that for my web development I use Coda, which I believe to be the best web development IDE available. I believed this even though it had quite a few niggling flaws and some features I would have loved to see. Yesterday, they added one of them – Subversion, built right in! Before, I used a terminal tab to commit and update my local source, but now I don’t need to! Yay!

Panic do some very cool software other than Coda – Transmit is a very good FTP client, and though I haven’t actually used any of the other software, I’m sure it’s of a brilliantly high standard. Also, they have cool offices.

08
Jul

FB: Updating the Profile Box

Further to my previous post regarding updating the user’s profile box on a Facebook application, I found this site which shows you how to update everyone’s profile content in one go. Of course, this means its Asynchronous, which isn’t exactly what we want, but it appears this is the best Facebook allows for now. Obviously this poses a number of problems:

  • When to do the update. Since there is the opportunity to have people from all over the world using your app, there’s very little chance of there being actual downtime in which all the updates can take place. Similarly, if you need to update things once a day at midnight, you should really be checking which country the user comes from and update their profile content at the right time.
  • Resources. If you’ve got thousands of users, how do you process all of them without killing your server? There are,of course, many solutions to this (I’ve implemented something similar to this on a project of ours at work), but I think they’re all pretty resource intensive. In the worst case when everyone’s profile is different, even caching won’t help you.
  • How often to do the update. This of course depends on the nature of your application. With Blaccu, currently I only update everything once a day, but of course the weather will be changing many times during that day (subsequent visits to the canvas page / using the refresh button on the profile page do refresh the profile with the current weather, however), so it would be ideal to have it update many times during the day. This isn’t so bad now when I don’t have many users, but what about when (/if) I’vegot lots of users?

All things considered, this is a bad way of doing things, and it’s Facebook’s fault. I would love to see a way of making an Ajax call when the page loads, so that the content in the profile box could be drawn in asynchronously and be completely up to date. We’ll just have to wait and see, I suppose.

21
Apr

IE Italics and Floats: What were you thinking?

I just came across the most ridiculous big ever. I had a page which had a number of similar blocks: each had an image floated left and some text next to it. One of the blocks of text had some italic text in it, specified by an <em> tag. For some reason, the whole block of these was rendered below the floated image, as if that block of test had been given clear: left; or clear: both;. The solution wasn’t easy to find, but was easy to implement:

em{ zoom: 1; overflow: auto; display: inline; }

What really gets me is that somewhere, someone programmed IE to do this. Either they’re part of some humongous joke which the web development community just doesn’t get, or they’re just a bit stupid.

Having said that, it’s obvious that someone is lacking quite a bit of sense when they appoint this man CEO.