The Danger of Unobtrusive Javascript

Unobtrusive javascript is a great practice to follow. Having pages that can fall back to real links and requests if javascript is unavailable is a great safeguard. The thing is, though, that we sometimes don't really expect things to be invoked that way. It is just a fallback, right? We may forget to test screens down the road that are never supposed to be used like that. You know, like that form that is always rendered through ajax into a modal window.

You are being a good web developer and using jQuery or Prototype or whatever and have all your event handlers attached in the DOM onload. What that also means is that someone on a slow internet connection might take a few seconds to load your page. During that time, if they click any of your anchor tags with hrefs that are supposed to invoke ajax calls, it will actually browse to the page since the onload hasn't been executed yet.

So, they click that link and bam! There they are at some page that was supposed to render in a modal window and now looks ridiculous as an actual page since you haven't seen it that way in a dozen iterations. Whoops!

What Kind of Developer are You?

I always hear people described as being a back-end guy or a front-end guy. Really, I think those terms are a little ambiguous and can be a little misleading. Or worse, you can get pigeon-holed into one or the other and then people don't trust you with half of the system.

At my current gig, I am generally regarded as a "front-end guy". That is largely because when I started working on the web application there, the whole thing was in shambles. I mean, it worked and generated a ton of revenue, so in that sense it was a success. However, the UI looked ridiculous, the code left a lot to be desired, and the page load performance was abysmal. I was constantly on my soap box about it and so the title stuck.

The problem with the application wasn't that the developers were not good. In fact, that company had a great collection of fantastic developers. The problem was actually two fold. From the development side, there was never anyone on staff who was a real expert on how to assemble a web stack. On the business side, no one really knew how to design a web front end and there was no graphic designer anywhere in the company.

If you are working on a web application stack, everyone needs to be a front-end and a back-end guy. The fact of the matter is that it is a front-end application and even though it has a front-end and back-end portion, most likely everyone is working on every part of the application. I know I have always worked on the whole stack, from top to bottom. These days, my knowledge base is weighted towards the presentation layer, but I have my fair share of experience creating database schema, building ORM mappings, writing nightly scripts, setting up and deploying servers, etc. I feel totally comfortable doing that stuff and enjoy it just as much as I do making wild UX implementations.

It is natural that some people are better at certain aspects than others. Some people are jacks of all trades and decent at each layer. Anyone who can only work on one layer though, is probably having a tough time finding a job or, if they're lucky, is coasting at a BDC.

I think one of the key factors of success is knowing and embracing your identity. Despite what anyone thinks I am, I am a front-end application developer who works the whole stack, but has special expertise in the presentation layer. It works really well when I am paired with someone who is the exact opposite and is a front-end-application developer who works the whole stack, but has special expertise in something that I am not an expert in.

Right now I am working on a real back-end system. No application container, no presentation layer, just a lean and mean environment for doing an incredible amount of heavy duty processing. It really is coming together as a great system thanks to the team and especially the tech lead, who is an elite developer/architect. I feel like I am making a meaningful contribution, despite my unofficial title as the front-end guy. The best part about it though, is that I get to work with some really fantastic people who have skill sets that compliment mine and can teach me lots of new tricks.

So, what kind of developer are you?

Dynamic Positioning with jQuery

I have been working on a few sprints lately that require some javascript to do dynamic positioning of a DOM element on whatever was just clicked on the screen. Here is a sample of some of that code. It assumes that there is an element, a.some_link, that when you click it the dynamically positioned element, #DP, places itself just to the right and centered vertically. It will also detect if positioning to the right will cause it to be off the screen and flip it to the left side instead. The only CSS requirement is that #DP be "position: absolute;". [js]$("a.some_link").click(function() { //Get the coordinates of the clicked element. var cellPosition = $(this).position(); //Add the left displacement to the width of the trigger, //placing the DP just to the right of it. var horizontalPosition = cellPosition.left + $(this).outerWidth(); //Here is the fancy part. If the position plus the width of your DP //if greater than the window width, change the position to the left //side of the trigger. if (horizontalPosition + $("#DP").outerWidth() > $(window).width()) { horizontalPosition = cellPosition.left - $("#DP").outerWidth(); } //Center your DP vertically on the trigger. var verticalPosition = cellPosition.top - ($("#DP").outerHeight() / 2) + ($(this).outerHeight() / 2); //Update the position of your DP. $("#DP").css({top: verticalPosition, left: horizontalPosition}); });[/js] Also note that if you were to call "animate" instead of "css" in that last call, then it would animate the movement instead of just snapping it to the new position.

Apple Airport Extreme Update - Lesson Learned

Tonight I updated the firmware on my Airport Extreme to version 7.4.1. When the device went to restart, I shut off the Airport Utility software and went about my business. I quickly found that my Airport was rendered completely useless by this update. After power cycling the router a few times and rebooting my Mac, I still had no luck. I could connect wirelessly but not access the internet. I could connect via the Airport Utility, but couldn't bring up the management screens because of an error "-5" saying something about not being able to read the configuration.

As it turns out, shutting off the Airport Utility during the middle of a firmware update will ruin the configuration on the router. If you update the configuration and cause it to restart, you can shut it down just fine. Doing an update to the firmware is a different case though. I ended up having to hold down the small unlabeled reset button on the back of the device for 5 seconds with it plugged in to reset the configuration on the device and now it is up and running again. Of course, I had to redo all my settings. Not too big a deal though.

After that, I updated my Airport Express to test my theory about shutting off the software. This time, I let it run all the way through before I shut it down and the firmware applied just fine and the device worked again right away.

You'll learn something new every day if you aren't careful.

How to use a sqlite3 database in your iPhone app

Using a sqlite database in an iPhone app is actually really easy. The only real requirement to get started is that you need to create a sqlite database to include, which is very easy to do.

Step 1 - Create the Database

Make sure you have it installed. If you don't have it, it is available through MacPorts. Once you have it, just type on the command line:

sqlite3 test.sqlite3

This will create a new database called "test.sqlite3" and set you up in the sqlite prompt. You will need to create your tables here. For this example, just type:

CREATE TABLE iphone_test ( id INTEGER PRIMARY KEY, value VARCHAR(255) );

Now you need to put some data in it:

INSERT INTO iphone_test (value) VALUES ("This is value 1"); INSERT INTO iphone_test (value) VALUES ("This is value 2");

Not too bad so far. Now just type .quit and you are all set. Copy your database into the Resources folder of your Xcode project and you are ready to move on.

Step 2 -Prepare Your Project

You need to link the sqlite3 framework library to your project. All you need to do is right-click on the Frameworks folder and select Add > Existing Frameworks... then select:

/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/usr/lib/libsqlite3.0.dylib

Step 3 - Add Some Code to Your AppDelegate.h

Open up your AppDelegate.h and add an import for sqlite3.h so you can use sqlite. Then this declaration inside your @interface so you have a nice handle to the database:

sqlite3 *database;

Then add these prototypes for the methods we are adding to the AppDelegate.m:

- (void)verifyDatabase:(NSString *)databaseName databasePath:(NSString *)databasePath;

- (NSString *) randomRecordContent;

Step 4 - Add Some Code to Your AppDelegate.m

Open up your appDelegate.m and add this method in somewhere. This will make sure that the database file exists in the user's file store and if it doesn't, it will copy it over from your application code.

- (void)verifyDatabase:(NSString *)databaseName databasePath:(NSString *)databasePath { NSFileManager *fileManager = [NSFileManager defaultManager]; if (![filemanager fileExistsAtPath:databasePath]) { NSString *databasePathFromApp = [[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName]; [fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil]; } [fileManager release]; }

Then add this code inside your applicationDidFinishLaunching method to get the location of the database in the users phone:

NSString *databaseName = @"test.sqlite3"; NSString *documentsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0]; NSString *documentsPath = [documentsDir stringByAppendingPathComponent:databaseName];

Now call the verifyDatabase method to copy the database from your app code to the users file store in case it isn't already there.

[self verifyDatabase: databaseName databasePath:databasePath];

Open the database so you can use it throughout your application:

sqlite3_open([databasePath UTF8String], &database);

Don't forget to close the connection in your dealloc method:

sqlite3_close(database);

Finally, add in a method that will read something from the database. In this case, we are adding the implementation of randomRecordContent that we specified in the header.

-(NSString *) randomRecordContent { NSString *theValue; const char *sqlStatement = "select value from iphone_test order by random() limit 1"; sqlite3_stmt *compiledStatement; if (sqlite3__prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) { while (sqlite3_step(compiledStatement) == SQLITE_ROW) { theValue = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)]; } } sqlite3_finalize(compiledStatement); return theValue; }

Now you are all set. As long as you have a handle to your AppDelegate, you can call this method and grab something from the database. For example, if you are in your view controller you can get a handle and call the method like this:

YourAppDelegate yourAppDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate]; NSString theValue = [yourAppDelegate randomRecordContent];

So there you have it. Hopefully that code is pretty readable. Please post comments or e-mail me if you have any questions.