jQuery Plugins: Column View, Part 2

February 2nd, 2011 by JohnO

So in the first part we talked generically about some design decisions surrounding making jQuery plugins. Now, I want to focus specifically on my Column View jQuery plugin and some of the design decisions I needed to make when writing it.

I really knew I only had one requirement beyond reproducing the metaphor from OS X’s Finder. I knew it had to be dynamic. I couldn’t just ask whoever wants to use this to display all of their column data onto the page and link them all together. It would create a nightmare to maintain or even develop in certain situations. So, that meant I needed to create DOM elements.

But, I knew the user needed to be in control of the DOM. They need to style, place, and size the entire column view widget. Some plugins (e.g. Fancybox, which is fantastic) take the other route by doing all the DOM work for you. All you do is provide the content. For that kind of plugin the design decision is perfect – it is a lightbox, it needs to a do a lot of DOM work and styling to accomplish the task.

So I decided to only manipulate the DOM once during the setup of the plugin; I take the contents of the node and place that in the first column:

1
div.html(columnview.contents().detach()).appendTo(columnview); //replace contents into new column

This way any developer can style the node they designate as the column view widget and I leave that entirely alone. They can be sure that their work remains intact and functional.

To keep the metaphor going and keep the widget dynamic, I also needed to add a way to reload a specific column. When you make a new file or folder in the OS X Finder you can see it right away in the column. To accomplish this, I needed to store the loaded url of each column. As I described last time, the best way to store data is with jQuery’s `data` method, so whenever a column’s contents are updated I place the called url onto it’s DOM node with a `data` call.

I am sure there are lots of different ways to accomplish this task. By defining my one operating principle (being dynamic) all my execution questions could easily be answered. Overall I got a very minimalist approach that would not get in a developer’s way. Some might label this as “unpolished”. But I disagree. Write as little code as you need to the job done, right? I’d like to hear if you agree or disagree? Or perhaps, what else you think this widget needs to do, or could do?

Django signals and comment denormalization

January 26th, 2011 by Kevin Grinberg

Last week we launched Legalbump, a legal news aggregator in the style of Digg/Reddit/Hacker News.

Standing on the shoulders of giants (as we like to do in the Django world), we used several pluggable apps to provide some of the core social features you’d expect: comments and voting. In particular, we used django-voting and django-threadedcomments (be sure to get the latter from GitHub – PyPi has an older package, 5.3 at time of writing).

Both are very flexible packages and provide template tags to get vote and comment counts (django-threadedcomments in particular is almost a drop-in replacement for Django’s contrib.comments, so you can use {% get_comment_count for entry as comment_count %}

However, the price of that flexibility is (some) performance drag. In particular, both apps end up making a LOT of queries (the precise number and impact of which you can discover for yourself via the invaluable django-debug-toolbar). One strategy to ameliorate that is caching; another is some denormalization (which, in effect, is another form of caching). In this case, we decided to start by denormalizing the comment counts, so that instead of making a separate query to get comment counts for each item, we store that information with the Post object itself (which we retrieve anyway for all of the list displays).

The first step is obvious: add a num_comments = models.IntegerField(default=0) field to our Post model (and of course make the appropriate migration). Then, define a method on the Post model to get the actual comment count – luckily, django-threadedcomments makes this a one-liner:

def get_num_comments(self):
    return ThreadedComment.objects.filter(object_pk=self.id).count()

So then the only remaining question is “how do we update the comment count whenever someone comments?” One less-than-elegant method might be to override the Comment.save() method; another might be to add an extra step in the view. However, these are both, well, ingelegant and hackish. Luckily, Django provides just the right piece of infrastructure to get the job done: signals!

To quote Django’s superb documentation:

[signals] allow decoupled applications get notified when actions occur elsewhere in the framework

In a nutshell, we can use the Django signal dispatcher to tell our Post object to “do something” when a ThreadedComment is saved. So, to update the comment count when a new comment is added, we’d do something like:

def denormalize_comments(sender, instance, created=False, **kwargs):
    instance.content_object.num_comments = instance.content_object.get_num_comments()
    instance.content_object.save()
models.signals.post_save.connect(denormalize_comments, sender=ThreadedComment)
models.signals.post_delete.connect(denormalize_comments, sender=ThreadedComment)

Credit where credit is due: this approach is modeled on a django-snippet that does something very similar for vote counts (though Legalbump’s actual vote denormalization is a bit more complicated, since it accounts for both Comment and Post votes).

It doesn’t take much imagination to see how this approach can be used to set up all sorts of interactions between apps without necessarily touching the apps themselves. Indeed, many well-written Django pluggable apps send their own custom signals.

Finally, a quick word of caution: despite being “separate” the actions triggered by signals are still executed inside the original HTTP request. So if you’re using signals to kick off some complex or long-running process, consider an asynchronous task queue (i.e. django-celery), so that these tasks run outside of the request.

JQuery Plugins: Column View, Part 1

January 19th, 2011 by JohnO

I recently had the task of replicating the OS X Finder’s Column View for a web application we are writing. The app itself is not quite done – but the columnview plugin is already out for public use.

I am one of those few developers who really like working with JavaScript. Because of my affinity I have gotten a lot of JavaScript projects over the years. As far as I am concerned, jQuery is the bee’s knees for working in JavaScript – it captures the natural feel of the language while exploiting its features (e.g. lexical scoping). So for a long time I just worked on these projects writing the necessary code to “get ‘er done”… creating a sloppy mess. These days I am concerned about the architectural issues – and I am not the only one. Questions around jQuery plugins are some of the more common I see on developer community sites like StackOverflow. With these questions circling I wanted to explore the topic in two parts.

First, I want to talk about creating jQuery plugins in general. Second, in the next post I want to talk specifically about this plugin and some of the design choices I made along the way.

What I am writing about here comes from some experiences and, more importantly, the jQuery Authoring Plugins Page. I am going to assume you understand and agree that cluttering the global namespace is considered “Bad Form” and will get you snide looks at parties. You also understand singletons and closures. There are wonderful resources only a-google-away if you don’t, but I won’t be providing them here. With that out of the way, this is the generic jQuery-approved boilerplate for creating a new plugin:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(function ( $ ) {
    var methods = {
    ...
    };
 
    $.fn.columnview = function(method) {
        methods.columnview = this;
 
        if ( methods[method] ) {
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof method === 'object' || ! method ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist on jQuery.columnview' );
        } 
 
        return this;
    };
})( jQuery );

The jQuery folks ask that a single plugin does not create more than one entry into the jQuery namespace (if you peek at their authoring page you’ll see the “Not Like This” example). So you stick all of your plugin’s methods into the methods singleton. You place both the singleton and the actual assignment to the jQuery object within an anonymous function and call it immediately. This prevents any of your code from leaking out into the global namespace. You’ll notice the code inserted as your plugin into jQuery is only 11 lines long. All your operations should occur in your methods.

So what do these 11 lines do? Three things. First, whichever jQuery object you called the plugin from is set in the singleton, making it available to all your methods. The method’s `this` context will not be the jQuery object you called from the outside so you absolutely need this reference. Second, when you start up your plugin, like so:

1
2
3
$('#columnview').columnview();
// or like this
$('#columnview').columnview({my:'options', go:'here'});

…it runs the init function (you’re going to have to define one) with the singleton you (optionally) pass in (line 12 in the code snippet). Third, you can call a specific function on the plugin, like so:

1
$('#columnview').columnview("refresh_column", 1);

That would call `methods.refresh_column` with the argument of `1` (line 10 in the code snippet). If you have ever used the jQuery Dialog plugin you have done this with the `close()` method.

There is one more question (really more like a wall) that people run into. It happens with more advanced JavaScript use, the nature of the language itself, and the event driven model we use on the web. Data?! Where do we put it?! Normally we’ve got classes with variables or a database to hold all our stuff. Now we’ve got a singleton and we could put stuff in there. But the singleton belongs to everyone and it can get messy sticking things into arrays (which end up resembling a struct from C). Developers coming from more “normal” programming ecosystems don’t consider the DOM as a place to store things. The DOM in JavaScript can, and should, be thought of as your data-store. jQuery has a handy function to do this storage for you: `data()`.

Data takes a key and a value and sticks it onto a DOM node. It does not put it on the jQuery object (which easily gets GC’d, lost, found, buried in soft peat moss, and subjected to public inquiry [bonus points if you get the reference]) but on the DOM node itself. So you can always be sure to have the up-to-date value and get it from anywhere without any concern. Using `data()` saves lives and makes your brain hurt less.

Next time: we’ll delve into the columnview plugin specifically.

EDIT: Part 2 is up!

Beware of MyISAM

October 28th, 2010 by Kevin Grinberg

So, we spent an embarrassing amount of time here at AF HQ recently wresting with this issue – what seemed like a migration bug in easy-thumbnails (a Django image thumbnailing app to replace the now-basically-defunct sorl-thumbnail).

The symptom was a failing migration (we use South for schema migrations, and easy-thumbnails provides the migration scripts for itself). More than halfway through (migration #10 of 13 I think), we got an error about not being able to drop a foreign key:

db.drop_foreign_key(‘easy_thumbnails_source’, ‘storage_new_id’)
[...] raise ValueError(“Cannot find a FOREIGN KEY constraint on table %s, column %s” % (table_name, column))
ValueError: Cannot find a FOREIGN KEY constraint on table easy_thumbnails_source, column storage_new_id

The answer, which the title of this post sort of gave away, is that MyISAM doesn’t support foreign keys, and this particular database happened to have a few (and the server was set to create MyISAM tables by default… because it’s a per-server, not a per-database setting). Still, why did it take so long to track down the particular problem here? Because the error didn’t point to the ADD FOREIGN KEY statement, which would have made the problem fairly obvious, but rather the DROP FOREIGN KEY statement, which didn’t exactly illuminate the problem.

According to the docs:

“For storage engines other than InnoDB, MySQL Server parses the FOREIGN KEY syntax in CREATE TABLE statements, but does not use or store it.”

So the migrations blissfully buzzed through the foreign key creation, but died on the DROP. I’m sure there was a good reason at the time for this “we’ll just silently ignore your ADD FOREIGN KEY statement” behavior, but it makes debugging things like this pretty damn hard.

Moral #1: Just don’t use MyISAM.

Moral #2: See Moral #1. OK, that’s a bit rash; there are, of course, specific cases where MyISAM outperforms InnoDB; but InnoDB should really be the default, and it’s a damn shame that on many systems it isn’t.

New Partners & Neighbors: Above the Fold

October 12th, 2010 by Kevin Grinberg

We’re excited to announce a new strategic partnership with Above The Fold, a fabulous user experience firm that we’ve collaborated with in the past and are pleased to call friends as well as colleagues.

Together, we’re going to be focused on providing a complete web & mobile application service offering – from user stories, wireframes and prototypes to design, development and post-deployment analytics.

We’re doubly excited because we’re not just going to be collaborating more closely with Above the Fold, but actually sharing space – a spiffy studio in beautiful (and occasionally sunny!) Central Square, Cambridge.

Above the Fold has a more complete write-up on their blog, which we highly recommend for all sorts of UX/UI insights – so we’ll just add that we too are super-excited about the partnership, the space-sharing, and the awesome things we’re going to build together.

Ground-Up Android, Part 5: Tweeting and Debugging

October 7th, 2009 by Yoni Samlan

This is part 5 of a 5-part series on introductory Android development. If you’re just arriving, you should head on over to Part 1. Warning: While the general ideas and Android-specific code contained here still apply, the Twitter-specific portions are now outdated thanks to the so-called “OAuthocalypse,” Twitter’s phasing out of HTTP basic auth.

In Part 4, we dug into accessing our Views from our Activity’s code, and registered an OnClickListener to handle the user’s interactions with our button. In the final part (a big one!) we’ll cover using J2SE libraries, debugging, and Android permissions.

So far we’ve gotten a lot done without too much “boilerplate” coding, and that’s great. But what we don’t have (yet) is an application that leaves its mark on the world. After all, what’s a Twitter application if people can’t benefit from your 140 characters of deep, meaningful insight into the state of the world (or what you ate for breakfast)?

Read the rest of this entry »

Ground-Up Android, Part 4: Writing the Code

October 7th, 2009 by Yoni Samlan

This is part 4 of a 5-part series on introductory Android development. If you’re just arriving, you should head on over to Part 1.

In Part 3, we defined our layout and prettied up our app’s main screen. Now let’s get to the business of real coding – the stuff that makes the app tick behind the scenes.

Read the rest of this entry »

Ground-Up Android, Part 3: Describing Your Layout

October 7th, 2009 by Yoni Samlan

This is part 3 of a 5-part series on introductory Android development. If you’re just arriving, you should head on over to Part 1.

In Part 2, we started an Android project, poked around it a little, and launched an emulator. Now we’ll move on to making the app look like what we want.

You’ll notice I titled this part “Describing Your Layout,” not “Coding Your Layout” or “Programming Your Views.” This is because Android gives you the tools to define most of the characteristics of your Activity’s visuals in descriptive, not procedural terms. This helps speed up development, thanks to the nice GUI-based tools for layout, and helps you keep your programming logic out of the places you define your application’s outward appearances (and vice versa). It’s important to know that you could create your entire app in Java, writing the descriptive code for your layout procedurally in your Activity instead, but it’s a much better idea to keep things separate wherever possible.

The resources

We’re going to build a basic Twitter client, so let’s make it look like one. Let’s switch back into Eclipse and poke around at what we have so far. You’ll recall that besides our Activity’s Java file, we have layout and strings files in the res/layout and res/values folders. Let’s go check them out.

Here’s the basic layout the wizard created for us in res/layout/main.xml:

the main layout xml

The main layout xml

Read the rest of this entry »

Ground-Up Android, Part 2: Our First Project

October 7th, 2009 by Yoni Samlan

This is part 2 of a 5-part series on introductory Android development. If you’re just arriving, you should head on over to Part 1.

In the first part of the tutorial, we got Eclipse, the Android SDK, and the ADT set up. In this part, we’ll get into our environment, create our first project and poke around in it, and test out the Android emulator.

Fire It Up

Go ahead and fire up Eclipse, and if it asks, choose a workspace (the default’s probably fine for now). Click on the “new android project” button or go to File -> New -> Android Project.

Click the New Android Project button.

Click the New Android Project button.


Read the rest of this entry »

Ground-Up Android: Getting Started with App Development

October 7th, 2009 by Yoni Samlan

This is part 1 of a 5-part series on introductory Android development. Warning: While the general ideas and Android-specific code contained here still apply, the Twitter-specific portions are now outdated thanks to the so-called “OAuthocalypse,” Twitter’s phasing out of HTTP basic auth.

Thinking about testing the waters with Android development? Jump right in. We’ll build a neat little application that interacts with a web service.

Yup.

Yup.

Which one? Twitter, of course.

This is a web form of a talk I gave with Henry Cipolla, CTO of Localytics, at BarCamp Boston 4 and in a longer form at FITC Mobile 2009, updated to cover the 1.6 (“Donut”) release of the Android SDK. The slideshow portion of that talk covers the basic concepts of the platform and slides are available online. I recommend checking it out.

Read the rest of this entry »