P'unk Avenue Window

Archive for ‘Uncategorized’

Criticism, journalism: things are tough/awesome all over

April 24th, 2009 by Tom 2 Comments

I enjoyed last night’s Junto discussion on art criticism in Philadelphia but I’m puzzling over some fundamentals. The larger context went mostly unspoken.

All journalism everywhere is in deep sheep dip right now because print newspapers are dying.

At the same time, everybody’s a critic (ahem) thanks to the Interwebs.

Which means we have an overwhelming supply of armchair critique of everything— art, politics, sports, everything— but our supply of profoundly well-informed criticism is perhaps in danger.

But that last is far more an issue for politics (if you can’t afford to send stringers to Pakistan, your information is limited) than for art (there are people who choose to invest 20 hours a week in art, on their own dime).

Also, why is this discussion so centered on Philly? Who cares about locality? Okay, it’s an important color in the palette, but it’s not everything. And other media have already gotten the message that it doesn’t matter so much anymore.

Craft artists have moved en masse to Etsy. They can sell their work, they can get discovered. And criticism and commentary happen everywhere people care enough about the work. Geography is mostly irrelevant, except insofar as it informs the style of the work itself.

And I’m talking about craft artists who produce functional objects. The need to be in the same room with it before you buy it should be greater, not less, than the need to stand in a gallery with a painting. So why must fine art sales, and fine art criticism, be local? And dependent on the expense of galleries and print publication?

Local artist Katie Henry produces both sewn paintings and bags. To my knowledge her sewn paintings have sold only on a local basis, while it is completely impossible for her to keep a handmade bag in stock for more than eight seconds. But I suspect this is mostly because her paintings haven’t been listed on Etsy (hey, the lady’s busy enough as it is).

So why hasn’t fine art really arrived on Etsy yet? It could be as simple as a marketing decision on Etsy’s part. Perhaps a wise one. But that’s just an opportunity for someone else.

Sometimes, blogging is timeless

April 15th, 2009 by Tom No Comments

Sometimes Google doesn’t exactly rush pell-mell to index your blog. And when Google does index your blog, sometimes they don’t do it in a way that really helps your readers.

To my mind, blogs have two kinds of readers:

1. People who read it regularly, via RSS or similar
2. People who find individual articles via a search.

Category #1 isn’t really Google’s department. Fair enough.

Category #2, of course, is what Google Search is all about. Sure, 99% of queries are about “country matters” and every search engine has them down to a tee, but the queries you really care about are always in that 1% that’s obscure and weird and only mentioned in passing on one site ever. And Google’s capacity to actually find that stuff is the reason they took over the search world in the first place.

But for a while there, this really wasn’t working for the P’unk Avenue Window blog.

Searches like these (with the quotes, making them exact):

“Designing while intoxicated”
“svncampfire”

Were turning up other people linking to or talking about our articles, but they were not turning up the articles themselves. Results on our actual blog always turned out to be category pages or the home page… which, more often than not, didn’t feature that content anymore due to the addition of new blog posts.

This poses a problem because people don’t know they are interested in something like svncampfire until they need it.

I did quite a bit of research looking for an explanation for Google’s dislike of our individual article pages. I considered blaming our robots.txt file, the presence of dates in our article page URLs, and of course sunspots.

But in the process I finally got around to learning about Google Sitemaps. And more importantly, the Google Sitemap Generator plugin for WordPress, which is beautiful. There’s really no other word for it.

A sitemap is a simple file that spells out what pages are on your site and what their relative importance is. You can’t use it to increase your overall rank with Google, but you can use it to promote your individual articles at the expense of things that might otherwise seem more important to Google, like your category pages. Where before Google might only rarely bother to crawl back through your calendar archive links, now Google clearly understands that your posts are special and unique snowflakes that do not wither with age and should be taken equally seriously. And unless you’re giving out stock tips or weather reports, this is of the good.

The sitemap plugin will not only generate sitemaps for you, it will automatically update them whenever you post to your blog. Tweak the weightings using the handy control panel and you’re good to go.

There is, however, one catch that meant an extra week of waiting before Google finally caught on: the very first time you write a sitemap, you must submit it to Google manually via the Google Webmaster Tools. The plugin cheerfully informed me that it had already “submitted the sitemap to Google” without mentioning this little fact. So take care to follow through on that detail. You should be using the webmaster tools anyway!

The results are not perfect. Some searches that ought to bring up our individual articles still mysteriously bring up only category pages. And tweets consisting almost entirely of links to our articles (often using the hated URL shorteners, which Google doesn’t seem to translate) still often outrank the articles themselves. But hey, it’s progress. Most of the time we’re on the first page in appropriately narrow searches. It’s a big improvement, and I have a much warmer, fuzzier feeling about the usefulness of blogging on topics of lasting interest.

Ultimate Showdown of CMS Destiny

March 16th, 2009 by Tom No Comments

These are my notes from the Ultimate Showdown of CMS Destiny panel at #sxswi.

* Colleen Carroll – Palantir.net
* George DeMet – Palantir.net
* Matt Mullenweg – Automattic/WordPress
* Steve Fisher – Idea Market

DESCRIPTION

This panel will feature the results of an `Iron Chef’ style
competition pitting three teams of all-star Web developers from
the Drupal, Joomla! and WordPress communities against each other
to develop the same Web site in each of their chosen open source
content management platforms.

Super crowded

Decision making tools to decide between Drupal, Joomla and
Wordpress, the “three leading content management systems”

Wordpress the overwhelming crowd favorite in applause test.
I would not have put them in the same category of animal but with so many plugins perhaps they are now.

A comparison of the three:
http://www.goodwebpractices.com/other/wordpress-vs-joomla-vs-drupal.html

The same spec was given to three separate teams who were
challenged to build the site in their preferred CMS

Drupal theme song ha

Colleen Carroll at Palantir.net led the Drupal team.

Team Joomla… led by Steve Fisher of Idea Market…
instrumental theme song kind of a downer what the heck?

Joomla has blogging extensions called Tamka which fill in the
Wordpress gap

Team Wordpress led by the creator of Wordpress, Matt Mulleweg

Theme song: “it’s called Wordpress, it’s my CMS, it’s the best
thing to hit the web since porn” A++++

Leadership Evanston set the challenge… a community leadership
network site for Evanston IL and other communities

Build a web site for use by a community leadership program
Site should utilize a variety of web-based social networking and
collaboration tools
Site should be as generalized as possible and be able to be
downloaded for use by a wide variety of organizations and
communities.

The requirements given:

User accounts with granular permissions
Contact and application form
Listserv integration
WYSIWYG
Embedded content
Version control
Editable general pages
Image galleries
Events
News
Blogs
Classifieds
Wiki pages
Polls
Forums
Ratings
Banner ads
User directory

This strongly reminds me of the work we’ve done for Duke University with Symfony. Sure enough that experience has motivated us to create our own open-source PHP CMS, pkContextCMS.

To put together a spec for the job, they went to Mark Boulton of Design Ltd., the Five Simple Steps:
Designing for the Web guy. There were ready to go PDFs so it was
an implementation challenge mostly… makes sense, front end layout wasn’t the challenge here.

No more than 100 hours could be spent.
Only freely-available software could be used, all sites must be
freely available.
Site must function on provided shared hosting (LAMP). Shared
hosting = bad permissions = ow, but they wanted to simulate realistic low-cost environments for nonprofit sites. Fine, but why not go with Slicehost or other low-cost virtual machine hosting for a little security and sanity?

Joomla team’s comment: “Specs From HELL”

Drupal guy: “building a web site in Drupal is a lot like making
a car out of bacon. It’s not much fun getting there but once you
arrive it’s delicious.”

2 weeks ago at midnight was the deadline…

drupalshowdown.com has the drupal site. They went with all your
base content. It doesn’t seem to do much.

The Wordpress site implemented the Derek Zoolander Center For
Children Who Can’t Read Good And Wanna Learn To Do Other Stuff. Definitely the best sample content.

The teams were spread over eight time zones etc, the Joomla team
have never met, the Drupal team went out of their way to work in
the same room.

No live demos which is disappointing. I really think they should
have done that. Now we’re hearing them talk about what the
experience of building the sites was like, which doesn’t really
give us much insight into how the tools compare or how the
results compare.

DeMet: “Did this feel like Drupal to you or were there parts
where you felt `this is difficult for Drupal?’” Carroll: “no.
Drupal’s awesome.” Later she acknowledged that breadcrumbs are
kind of a pain in the ass in Drupal. Fisher and Mullenweg:
“yeah, it’s built in.” “Yeah, we didn’t have to think about it.”

Mullenweg: the menu system got big and crufty.

This is an example of why Refresh Philly isn’t hooking up
nonprofits with volunteer coders yet… the results are
intriguing but sustainability and maintenance are big questions.

All three teams seem to have found bugs and contributed features
back during the project.

They all had fun and wrote theme songs and built web sites. Not
a lot of takeaway here.

The Wordpress guys wrote by far the most custom PHP and JS code
at 1,808 lines. Drupal and Joomla! went with 220 and 30
respectively. But how well did they implement the spec? If they
all did an equally good job that would mean something…

Ah the WordPress stats included theme files which the others did
not. So never mind.

The designer called it a tie between WordPress and Drupal and
dinged the Joomla! team for not following his typography…
which doesn’t say anything about the relative usefulness of the
CMSes.

Okay finally… they did do some user evaluation with users who
didn’t have a CMS preference already… finally the crux of the matter

All three sites involved quite minimal amounts of new PHP, which
emphasizes that all three have core features and plugins enough
to more or less stamp this site out as far as the back end is
concerned.

drupalsxsw user testing summary: “I don’t understand this, and
all the forms are too complicated, where why what OH GOD
SPIDERS”

The joomla user test hit problems too and she would retry and
retry and retry kind of banging the point home

The Wordpress dashboard still had the Wordpress development blog
on it ouch

It’s possible they didn’t give her an account with the right
privileges to do anything? Oh they tried it at multiple
levels of user auth. Why not show us more representative video then?

The user tester found joomla and drupal the most useful and
wordpress a distant third. She had a lot of difficulty finding
the administrative features for the wordpress site’s
site-specific features.

cmsshowdown.com will have links to everything soon.

They did not evaluate performance issues.

“How much time was spent making the site look right in IE6?”

“Too much.”

“We almost forgot. Last hour. IE6: crap!”

Drupal used the Zen theme which has that under control already.

No one used all 80 hours.

And now the beauty contest… the
audience objected loudly to being asked to vote when they
weren’t shown demos of the sites. I agree. And I never quite heard who won. I had something else to attend to. Here’s a tip: never shave your head with a cheap disposable razor.

Notes from the “iPhone development for experienced web developers” SxSW Interactive panel

March 15th, 2009 by Tom 3 Comments

Quick and dirty notes on an excellent panel.

Joshua Siler, babcock jenkins VP of Tech, web developer
Jordon Lev, senior developer

[I know some of this stuff already, comments from me are in
brackets]

They do relationship marketing for sun, linkedin, intel, IBM,
business to business in general. They are interested in metrics
and so on

So they did an iPhone app related to that

I am surrounded by netbooks

“web developers are mad for power.” Because we’re used to
insanely lazy tools that can casually abuse database servers and
application servers and the desktop CPU and it all works anyway.
The iPhone does not work that way.

400mhz processor, 128mb RAM, 10 to 100 times slower than a
powermac G5. “Premature optimization” is not so bad in this
environment. You can’t process 5 megs of XML and turn them into
a graphics display on the fly. [This is why Objective C is more
appropriate than JavaScript and Canvas if you want any speed]

People expect immediacy on iPhones. The latency of web pages is
something people are conditioned to only for web pages. Also the
browser displays that it is still loading stuff in multiple
ways. iPhone app developers are responsible for doing that on
their own.

Slow stuff should be asynchronous where possible (but remember
that this can lead to a lot of confusion if it’s poorly done).

Objective C is not in the top 20 programming languages based on
search results. It’s all the way down at #2, behind COBOL and
FoxPro and Ada etc. It’s just barely more widely discussed than
Scratch or Haskell.

Objective C means you’re dealing with pointers and memory
management (without garbage collection- it’s up to you to free
things you don’t need anymore, and not free them twice).
Multithreaded code is common (PHP doesn’t have threads). As for
the syntax… he refers to it as “syntactic saltiness” rather
than “syntactic sugar.”

[Why can't Java source, or almost-Java source, be compiled to
Objective C source and so on? Could a subset of PHP be compiled
to Objective C, creating a new audience of programmers? Did I
sign away the right to even try to create something like that?]

Xcode is the development environment, practically speaking,
period the end. You could edit your source in Textmate and
switch back and forth maybe.

Cocoa, on the other hand, is modern and nifty and generally not
an experience you’ll hate. High end UI controls can be dragged
and dropped into the application’ UI and they will scroll and
bounce and do all that stuff on their own. You populate them
with data and go on with your life.

iPhone 3.0 OS will of course make all of this obsolete next
week… well not very… but the preview means it’ll be a more
serious change perhaps than previously

[Apparently I'm legal if I seek to create a compiler from
something friendlier to Objective C. Interpreters are forbidden.]

Data connection is flaky. [What does that mean? Lost packets in
the middle of documents = not normally possible with TCP, it
just dies outright. I assume they mean connections dying halfway etc., which is possible in TCP]

REST, with JSON responses from the server, is vastly more
efficient than SOAP and other heavy XML stuff and they like it
for devices like the iPhone. And it just so happens I made
exactly the same choice for pkMediaPlugin’s API because of the
simplicity of it all.

What are they using to parse JSON in Objective C?

Cocoa is big on events and delegates… message passing is used
to communicate between objects. Rather than calling something
and waiting for completion, you are more likely to receive a
message when the work is done.

Interface Builder places text boxes, buttons, etc. on the screen
in a friendly way, but the code to make them do anything is up
to you.

You can create multiple “views” (distinct screens / pages of the
application’s interface) and use buttons to swap between them.

The app delegate class is the “main function” or “master
controller” of your application.

We use @synthesize rather than `new’.

The RootViewController corresponds to the default view, you can
add more views and you often build your app out of a few views

[Not sure why "model" and "view" classes have names like
"WebsitesDataController" and "SettingsViewController". Is this
their own private convention? It's weird.]

[Here's a json library for objective c:
json-framework ]

They used SBJSON instead.

return [jsonParser objectWithString:jsonString error:NULL];

Why didn’t they do this as an iphone-safari web application?
Response time (JavaScript is certainly slower than Objective C)?

Their answer: users like apps. [Also an app ought to be faster because compilation/interpretation of JS and HTML and CSS is not required.]

[UIAlertView openURLAlert = [[UIALertView alloc]
initWithTitle:@”Connection Error”… ]
[openURLAlert show];
/* Forgetting this would be Bad; we have to manage stuff
ourselves */
[openURLAlert release];

You write a cellForRowAtIndexPath method for your table view and
bam, Cocoa starts calling that to get content for that cell when
it’s visible etc.

[Ask them to elaborate on "autoreleasing" things... I did, see the end]

// alloc allocates a raw object, init is what we think of as a
constructor
// settingsController is a pointer
SettingsDataController = *settingsController =
[[SettingsDataController alloc] init];

// Now we give those resources back

[settingsController release]

* * *

They like:

Exciting platform
Standardized hardware
Cocoa and MVC
Bare metal programming is kind of exciting for a change

They don’t like:

Objective C
Refactoring is hard. Objective C just doesn’t accommodate DRY
very well

(of course, PHP is not totally great that way either, he’s used
to Ruby)
Lots of assumed knowledge and undocumented stuff
Xcode is crude
App deployment is a pain
Flaky connectivity
Apple controls the universe

[These guys are not the most experienced iphone developers in
the world, but they are smart and successful and have a valuable
perspective similar to our own... very similar to what ours
would be minus my past C/C++ experience]

[I asked about autorelease and memory pools as an alternative to
alloc/release. They don't really know the answer to that one. However:

http://www.cocoadev.com/index.pl?AutoRelease ]

The Past Didn’t Go Anywhere

March 4th, 2009 by Tom 2 Comments

Why back in my day we walked uphill both ways through slushing sleeting flaming hydrogenated bat oil without iPhones and we liked it. Youngsters today have no [INSERT NOUN HERE].

Okay, so sometimes the old ways are retarded. Entertaining to read about, but retarded. We no longer have to write video games in 2K of ROM (English translation: considerably less than a printed page’s worth of information). Better yet we’re not stuck playing them.

But sometimes, insane constraints produce beautiful solutions.

atariadventure


5seven5

twitter_logo_125x29

These days most web sites employ dynamically generated graphics, even if it’s something as simple as generating and displaying thumbnails of a photo. This is typically done with tools like the gd library, which I originated, or ImageMagick.

Both of these tools assume you have a lot of memory to play with. This is a reasonable assumption for two reasons:

1. It’s 2009. You do have a lot of memory to play with.
2. Both tools let you draw things on the fly on top of an image (creating charts and graphs, for instance) and then save it again. The sensible way to do that is to load the entire image into memory as a nice, convenient two-dimensional grid of pixels.

Trouble is, that two-dimensional grid of pixels can be pretty darn big. Sometimes even by modern standards.

That ten-megapixel camera you just bought? It creates images that take up ten megapixels times four bytes equals roughly forty million bytes of memory when you load them up with the gd library (usually via PHP’s imagecreatefromjpeg function).

Is that a dealbreaker? Well, your server probably has at least 2GB of RAM in it, and virtual memory besides. But that’s not the whole story. Most sites are deliberately set up with much tighter limitations on the amount of memory that a single PHP request can use up. And when dozens of people are uploading huge photos at the same time… well, there are good reasons to have those limitations.

So we’re back to the old days. That damn red dragon is going to eat us if we don’t find the sword to kill the memory monster.

Enter the netpbm library: a collection of sweet, simple command line tools for playing with images. A collection of tools that dates back to 1988… an age when you might just barely have enough memory in your computer to hold one half-megabyte, low-resolution photo.

So these tools don’t load the whole picture into memory at once. They load it one line at a time, or as many lines as they need to do the job in question, and they deal with those lines and pass them on to the next tool in the chain. You can read, resize, and re-save an image without using prodigious amounts of memory.

The netpbm tools are part of the Unix tradition, and they take advantage of the Unix concept of pipelines, which allow you to “pipe” the output of one program into another, and pipe that on to a second, and on and on. And that allows for some extremely elegant things:

anytopnm < uploadedfile.bmp | pnmscale -xsize 600 | pnmtojpeg > outputfile.jpg

That pipeline accepts a file in almost any format, scales it so that it is 600 pixels wide (preserving the aspect ratio), and converts it to a JPEG without ever loading the entire beast into memory at a single go. It loads just the rows it needs to see as it proceeds through the file. This isn’t suitable for everything, but for scaling, cropping and conversion it’s fan-freakin-tastic.

You can call that from PHP, using the system() function. But if you’re working with the Symfony framework, you might not need to. I’ve wrapped up some common netpbm operations in pkImageConverterPlugin. In fact, you should be able to use that plugin with non-Symfony PHP code, though I haven’t tried that myself.

You won’t be able to conveniently use it on a Windows host, though. The netpbm utilities exist for Windows but the Windows command shell is one of my least favorite things, so you’d have to make some minor changes to get my code working with it.

Macs, on the other hand, are Unix-based and will work just fine with netpbm and pkImageConverterPlugin, once you install it via macports or Fink.

In fairness I should note that ImageMagick supports caching images on disk rather than representing every pixel in memory. That amounts to simulating virtual memory within your program, which might sneak you past the PHP memory limit. But this is not as elegant or as fast as a set of tools designed for row-by-row operation from the get-go.

It’s good to let it all hang out and explore the possibilities of excess. But sometimes, restrictions are good things. And long after restrictions have been lifted, they can return in new forms and new situations. At which point we’re grateful to have the carefully optimized code of an earlier era. Y’know, before everybody had one of these:

martincooper_first_cell_phone

Frosted Lucky Tags, They’re Magically Persistent

February 25th, 2009 by Tom No Comments

I’ve been talking about progressive enhancement lately: the idea that web sites should start from a core of straightforward, highly functional HTML and build out from there. JavaScript, CSS, etc. should enhance the experience and improve ease of use, but they are not substitutes for meaningful HTML. Once you go that road, you can forget about accessibility, search engine friendliness, simpler browsing devices… it’s a long list.

But progressive enhancement isn’t limited only to the browser side.

This week I faced a task we’re all familiar with and none of us much enjoy: implementing a form with a file upload button.

File upload: the dreaded browse button

File upload: the dreaded browse button

There are many lousy things about the file upload button. But one of the worst is that, unlike regular form elements, if you present the same file upload button back to the user with their previous selection filled out… it doesn’t work. They have to browse for the file again. Which contrasts harshly with the way other input elements behave: as long as you present the user’s input back to them as the new default, they don’t have to enter it again. And if you’re asking the user to correct three or four things in a large form, you really, really don’t want to make them re-upload their resume on every single pass.

Now before you start hollering about security, let me say that I fully understand why the upload button won’t let you specify a default. In a word, it’s dangerous. Black hat web developers could specify any file on the hard drive… perhaps a file that often contains passwords on most people’s hard drives, for instance… and if the user didn’t triple-check, the black hats would then be in possession of the user’s personal information. Ouch.

What’s more, even if this did work, the user would still be uploading the file over and over. Which is slow. And when it isn’t slow, it’s expensive. One sure way to exhaust your bandwidth allocation and be invited to step up to an exciting new level of service from your web hosting provider.

So what do we do about this? We work around it… over and over. A common pattern is to accept the file provisionally even though the rest of the form didn’t validate, perhaps saving an object in a database but marking it “incomplete” until the user finishes the job correctly.

Of course, doing anything over and over is Repeating Yourself, and around here we frown on that sort of thing. I knew I wanted a real and lasting fix for the problem.

Enter Symfony 1.2 and its new approach to forms. Symfony 1.2’s forms offer lovely abstractions like widgets and validators. A widget represents an input element, file elements included, while a validator is responsible for determing whether a value is acceptable. They are very simple and well-factored and completely independent of one another.

Or they were until I got hold of ‘em.

Symfony’s approach is to validate fields and then present the form again if it fails validation, redisplaying the same values to the user. But if one of those fields is a file input field, this fails pretty badly: the user has to select the file all over again.

My new widget, pkWidgetFormInputFilePersistent, and its partner in crime, pkValidatorFilePersistent, break a few rules for the sake of the common good. But like all superheroes, they bend the rules for a good cause. And they only do it when you’re not looking.

By holding hands under the table, they are able to store the user’s initial upload attempt in a temporary folder and pass forward just enough information to allow that file to be automatically reused if the user chooses not to replace the file on the next validation pass.

File upload, first validation pass

File upload, first validation pass

Am I breaking the abstraction rules of Symfony? Well, yes, a little. But I’m doing it in order to reinforce the “anything the user enters, you can present back to them for further editing” behavior on which Symfony’s forms rely. When you substitute my file widget and validator for the regular versions, absolutely nothing changes… except that users don’t have to upload the same stuff over and over again. And we’ve eliminated a host of oh-shit-how-do-we-fix-this-now-that-the-client-noticed workarounds in different projects, all seeking to resolve this same issue.

One notable way in which I don’t cheat in this code: I take advantage of PHP’s really handy support for arrays in HTML forms. Perhaps you haven’t seen this trick before. When you write:

<input name=”dog[name]” />
<input name=”dog[breed]” />

… In your HTML, you might think it necessary to look at $_REQUEST['dog[name]‘] in your PHP code. But this isn’t the case. You receive an array instead, meaning that you can look at $_REQUEST['dog']['name'].

How does this help us? The apparent extreme simplicity of Symfony’s new widgets and validators initially made me think there was no way to manage both the file input element itself and a hidden element with a randomly generated ID for the file you uploaded on the previous pass, in case you decide not to replace it. But in fact a Symfony validator registered for ‘file’ will receive an array if the corresponding widget puts out elements named ‘file[input]‘ and ‘file[persistid]‘. And this works even if arrays are nested. Which means that Symfony widgets and validators actually have all of the information they need to implement complex controls.

This, then, is progressive enhancement on the server side. We’re able to preserve a simple and elegant approach to handling forms by encapsulating a tricky but worthwhile enhancement in a way that plays nicely with existing Symfony code. You don’t have to take a fundamentally different approach to use my persistent file upload widget in place of the regular one. It just makes things more awesome when it’s there. And that’s what progressive enhancement is all about.

You can check out pkPersistentFileUploadPlugin here.

The Upside of Static Cling

February 20th, 2009 by Rick 1 Comment

static

Last night, in considering possible post topics for today, I emailed myself the following:

Creating space to experience art, Bresson walking slowly backwards out of the room so as you want to follow him, Eno wanting to leave things out, while players want to hear themselves play. Making a cool medium from a hot one. Film with the lights off. White websites. A new function of modernism, subjective, interactive. John cage, lettng the audience hear itself, it’s contribution to the music. Trying to squint your ears to eaves drop after thinking you heard your name. Drawing in the audiences attention. Having them come to you, never demanding it.

Private, personal, contemplative aesthetics, subjective, conversational.

This morning I forwarded that to Alex, asking him to run a litmus test on the idea:

Just pick something that isn’t an argument built on top of your deep
vocabulary. If it can’t be said with simple words, fuck it.

What I mean is this: we eat carefully presented meals slower than we inhale reheated chili. When my mashed potatoes have a leafy garnish stuck in them I feel the need to meet the chef halfway. It makes me eat with as much care as went into the preparation of the food.

When a doctor whispers instructions in that hush way that gives us goose bumps we listen intently to every word. When our parents used to scold us we shut off and let the scolding wash over, perhaps some of it was absorbed as vibration through our skin.

In art this idea is leveraged through the use of negative space. We fill in the parts that are empty. In music we use the negative space to anticipate the next note. It creates drama. When something appears deliberately sparse or still we engage it to find out why it is so.

To expand on the examples I listed last night: I love Robert Bresson’s films because he makes us do work. He used non-professional actors, calling them models. They deliver their lines flatly, they move stiffly, the camera moves very little. He creates a very deliberate mystery with all of this negative space and we get sucked in to equalize the pressure.

In an interview for Tokion magazine a few years ago, Brian Eno mentioned an essay by Warren McCulloch called What the Frog’s Eye Tells the Frog’s Brain. The premise is: our eyes constantly fight off habituation. If we stop scanning a room the rods and cones stop transmitting new information. A frog’s eyes habituate on purpose. It’s what makes the fly buzzing about the main object of the frog’s interest. This idea has been put to use in Eno’s minimalist music for quite a while. He creates a ground for our ears to absorb, then plays with themes and accents that float above that ground.

That bit of positive space surrounded by negative is our fly. When it’s left room to breathe, we gobble it up.

Google, I love you but you’re killing the vibe

February 13th, 2009 by Tom 3 Comments

Once upon a time there was a web site. And the web site offered filters. And lo, the filters were good.

They let you browse for events at Brasils Nightclub. Or classes featuring Darlin Garcia. Or DJ nights within the city limits. Or any combination thereof.

And this was awesome. Until Googlebot arrived.

Googlebot, I love you. I really do. Hot, burning, profitable, whuffie-ridden love. But when you multiply all of the event types by all of the locations by all of the venues by all of the studios by all of the instructors by all of the genres…

Hoo boy, that’s a lot of URLs. And Googlebot wanted to index all of them.

Googlebot, I tried to break it to you gently. I whispered little suggestions in your ear. Suggestions like:

<meta name="robots" content="noindex, nofollow" />

… In pages with URLs that contain more than one filter. That way Google could index the listings for Brasils Nightclub but not every combination of Brasils and everything else. I want you to index me, Googlebot, I just don’t want you to index me to death. I do have other interests, you know.

But Google said “ohhh, you don’t want people to KNOW I followed that link! Okay. It’ll be our secret. I’m still going to follow it though. Because I LURV U.”

TOM: [Pained expression]

But Googlebot is so good to me, I couldn’t part ways with it lightly. I tried again:

<a rel="nofollow" href="http://salsadelphia.com/filtered/type,intermediate_class;venue,brasils">Tougher Classes</a>

But the more I played hard to get, the more ardent Googlebot’s love became. Googlebot honored my wishes in a sense— it didn’t kiss and tell— but it sure wouldn’t back off either. It became difficult to hold a conversation with anybody else.

My processor load was spiking. If you know what I mean. And I think you do.

Finally I turned to an old friend famous for her bluntness: Apache’s mod_rewrite module. And I begged mod_rewrite to do what I could not: cut Googlebot off at the knees.

And she obliged with panache:

  # Google has been ignoring my subtle hints not to
  # beat the crap out of the database by indexing
  # multiple filter combos. So be blunt about it and
  # explicitly redirect all attempts to access a
  # double filter (or worse) to the home page if they
  # come from Googlebot.

  # Filters are separated by semicolons, so this ain't hard.

  RewriteCond %{HTTP_USER_AGENT} Googlebot
  RewriteRule \; http://salsadelphia.com/ [L,R]

Did Googlebot take the hint? Well… sort of. It’s still banging the gong for me. But mod_rewrite tirelessly deflects Googlebot’s passion in a more appropriate direction:

66.249.72.65 - - [13/Feb/2009:08:55:06 -0600] "GET /filtered/genre,rueda;instructor,victor_colon;studio,prince_of_salsa;type,basic_class;venue,family_tavern HTTP/1.1" 302 302 www.salsadelphia.com "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

That’s right Googlebot— I totally freakin’ heart you, but if you push me too far you’re gonna be looking at my home page like everyone else.

Because my home page is cached for mass consumption. It’s something I can afford to give. If you know what I mean. And I think you do.

Edit: nope, robots.txt would not help with this issue. I remembered this from the Old Days, but thought I’d check in and make sure it’s still the case. It certainly seems to be: “note also that globbing and regular expression are not supported in either the User-agent or Disallow lines… you cannot have lines like “User-agent: *bot*”, “Disallow: /tmp/*” or “Disallow: *.gif”. “

Same Old Tom, Progressively Enhanced

February 11th, 2009 by Tom No Comments

Last week I announced a progressive enhancement script for select elements in web pages.

At the time, I didn’t know “progressive enhancement” was the proper buzzword for what I’d written. This is one of my pet peeves: even with Google, we still have to contend with the snottiness factor of the people who write web links. You can easily find what you want… if you already know what the kids are calling it these days.

But anyway: I have since been educated. Progressive enhancement is all about making web pages that are complete and functional as plain vanilla HTML and CSS, but more awesome in the presence of JavaScript.

As opposed to what? Well, the old catchphrase was “graceful degradation.” Sounds the same, doesn’t it. But there’s an important difference in philosophy that drives a difference in results.

Under the “graceful degradation” regime, designers created awesome websites with JavaScript, using HTML and CSS almost as an afterthought. Then they went back… sometimes at gunpoint… and made a more or less completely separate version of the page for Those Poor Losers Browsing At Work With Javascript Disabled. This version of the page was never as cool and rarely as functional. And something usually got left out.

“Progressive enhancement” is a fundamentally different approach. The web application is built first in plain-vanilla HTML, with all interactive features completely accessible through HTML forms and links. Then, if JavaScript is available, JavaScript code latches on to the plain-vanilla form controls and enhances them to provide a more attractive, responsive and usable interface… without changing the way the browser and server interact, except where it is actually beneficial to do so. More than one person has described it as a “layer-cake approach.”

My enhanced multiple select widget, and the alternative implementations that others pointed out, are obvious examples of progressive enhancement. Another is this jQuery-based ratings widget, which replaces a set of radio buttons with a more attractive interface when that is possible. Or this slider control that replaces a select element. Or the jQuery UI Tabs widget, which enhances plain ol’ UL lists and DIVs into a tabbed interface.

jQuery is especially well-suited to progressive enhancement because it is so good at assigning new behavior to any part of a document by selecting things by tag, class and so on, without sprinkling JavaScript code throughout the page. But there’s plenty of great progressive enhancement going on outside the jQuery community as well.

One of my favorite things about the progressive enhancement strategy is that it allows developers to develop, right away, while front end designers (there’s that term again) sweat not just the visual appeal but the visual interface.

Of course there are desirable ends that can’t be easily met purely by transforming existing form elements into pretty widgets. Sometimes there are major benefits to be achieved by submitting forms via AJAX so that the entire page isn’t reloaded, and that’s a major change in the way the browser and the server interact. But well-designed development frameworks like Symfony make it easy to detect whether a request is an AJAX request or an ordinary one, making it easier to gracefully handle the changes in behavior that are truly worthwhile.

I intend to advocate for a stronger emphasis on progressive enhancement both within P’unk Avenue and in web development in general. It’s a smart strategy that produces elegant, uncluttered and distinct HTML, CSS and JavaScript code.

pkMultipleSelect: a better HTML multiple select element

February 4th, 2009 by Tom 4 Comments

We’ve all been there (okay, the web designers have all been there): the client wants an interface that lets them pick more than one item from a list and submit them as part of a form. And HTML offers a tag for that:

<select name=”monkeys” id=”monkeys” multiple>
  <option value=”">Pick a Monkey to Add</option>
  <option value=”macaque”>Macaque</option>
  <option selected=”true” value=”rhesus”>Rhesus</option>
  <option value=”capuchin”>Capuchin</option>
  <option selected=”true” value=”howler”>Howler</option>
</select>

Which renders like this:

Everybody hates this control, because nobody understands it. On the Mac you have to hold down the command key while clicking in order to add one monkey at a time. On Windows the situation is similar: you must use the control key. Truly… it is a multiple select control that makes the baby monkeys cry.

Well my friends, today the pain stops. Today we have released pkMultipleSelect, a simple jQuery script that automatically replaces your multiple select elements with user-friendly multiple-select controls. No muss, no fuss, no user confusion.

All you have to do is bring both jQuery and pkMultipleSelect into your page with script src elements, then run one line of JavaScript code to convert your multiple select elements. Single-select elements, of course, are left untouched. And if you have elements that are created later, such as elements in forms populated by AJAX, you can easily convert those too as needed. Making it pretty, of course, is a job for CSS and we’ve made it straightforward to do it. Complete instructions are in the README file provided in the zipfile.

If JavaScript is turned off, you simply get the original multiple select control. Can’t get much more backwards-compatible than that. And yes, it’s been tested in IE6, IE7, Safari and Firefox. Edit: And Chrome, and Opera. This thing works, people.

But don’t take my word for it: try the demo!

Download pkMultipleSelect

Edit: er0k points out there is another implementation out there. I like that one too, but they have very different styles, so I think they are likely to serve different audiences.

Edit of the Edit: Ryan Cramer’s jquery-asmselect, on the other hand, is a superior implementation of the same idea. Very well tricked-out with jQuery effects and so forth, and so similar in concept that I’m smacking my forehead over here. I probably would not have built my own if I’d spotted this one first. Mine is more lightweight, so I think it serves a purpose, but if you find yourself wanting “the same thing but more of it” check out jquery-asmselect.