Tech Blog :: Tech Blog


Jan 30 '12 7:48pm

Reducing coordinate density in KML files (with a node.js script)

Lately I've been tracking my bicycle rides with an Android GPS tracking app. The app exports to multiple formats, including Google Maps and KML. I wanted to take all my rides for a week and overlay them on a single map, but the coordinate density was too high - thousands of points for each ride - so GMaps was paginating the maps to reduce the density, and the overlays didn't work.

So I needed some way to reduce the coordinate density of the KML files, taking 1 out of every N points, so the route looked the same on the map but with less unnecessary detail.

I tried to find an existing tool to do this, but couldn't find one. So I started writing one as a node.js script (I'm trying to do everything platform-neutral these days in node). First I tried to actually parse the KML using various XML parsers - but the parsers stripped the line breaks between coordinates, so the format broke, and I realized I didn't really need to parse the format at all. I just needed to eliminate some of the lines.

The result is a very simple, functional KML Coordinate Density Reducer. It reads each line of a KML file, uses regex to determine if it's a coordinate line or not, and if it is a coordinate line, strip all but every Nth line, as specified in the shell parameters.

Using the script, I reduced each route from thousands of points to a few hundred, imported them all into a single map, and can view or embed the routes all at once.

Update: Someone wrote an adaptation that also checks the distance between points. (See tweet.)

Jan 30 '12 11:39am
Tags

Git trick: Cleanup end-of-line changes

I was working on a site recently that was moved from one VPS hoster to another, and the ops team that moved it somehow introduced an end-of-line change to every file. I didn't want to commit these junk changes, so I wrote this little snippet to clean them. For each modified file (not new ones), it counts the number of changed lines, excluding EOL changes, and if there are none, it checks out a clean copy of the file:

git st --porcelain | grep -r "^ M" | awk '{ print $2 }' | while read FILE; do
  LINES=`git diff --ignore-space-at-eol "$FILE" | wc -l`;
  if [[ "$LINES" -eq "0" ]]; then
    git checkout "$FILE"; 
    echo "$FILE"; 
  fi;
done
Jan 17 '12 10:00am
Tags

Why Node.js? Why clients should ask for it, and developers should build with it

Following my post about my new node.js apps, and since I would like to turn New Leaf Digital into a node.js shop, I should write a little about why you, perhaps a potential client with a web project, might want to have it built in node.

Node.js is only two years old, but already sustains a vast ecosystem of add-on modules, tutorials, and meetups. The energy in the community is palpable and is based on strong fundamentals. Working in Node brings out the best parts of web development. Node is built in javascript, a language every developer knows (at least a little bit), so the learning curve is not a deterrent. That's important to consider as a client because, unlike other systems that have peaked in their appeal to developers, you can build a Node.js application today and know its platform will be supported for the long haul.

Node is truly lightweight: Unlike bloated Swiss army knife frameworks that try to solve every problem out of the box at the expense of performance and comprehension, a Node app starts as a completely blank slate and is only as complex as you make it. So you'll get more bang for your server capacity buck from the get-go. (I've worked on several Drupal projects involving performance, getting each page to load faster by eliminating cruft and bottlenecks. In Node that whole way of thinking is flipped on its head.) Every tiny operation of your app is also light: the whole system is built on a philosophy of "asynchronous" input/output. Think of a node app as a juggler: while each ball is arcing through the air, it's catching and throwing other balls. Interactions don't "block" the flow like a traditional web application. So you don't run out of capacity until you're really out of capacity, and a bottleneck in one part of the system won't bring down the rest of it.

This asynchronous I/O also makes node.js especially suited to applications involving file handling, interaction with external web services (as in Flashcards), or real-time user interaction (as in Interactive Lists). These are much harder to scale on traditional platforms, because the operations make other processes wait around while they're off doing their work.

Node.js is also perfectly positioned to work with new database technologies, like MongoDB, which offer a flexibility not available with traditional SQL/relational databases. Node.js and MongoDB both "speak" the same language natively - javascript - so building or working with JSON APIs is easy. Architectures can be "rapidly prototyped" and changed on the fly as the application concept evolves.

So what is node.js not good for? If you want a robust content management system out of the box for a news publication, for example, you probably want to stick with a platform like Drupal. If you want a simple blog with easy content creation tools and comments and photos, you're still safe with Wordpress. If you're building software for banks to transfer money across the globe, there are probably battle-hardened, traditional ways to do that.

But for almost any other web app, node.js might just be the best toolkit to build with. So please let me know when you're plotting your next big web idea!

Jan 17 '12 9:00am
Tags

Apps.newleafdigital.com: Building a suite of apps in node.js

I just launched a suite of node.js apps at apps.newleafdigital.com. Included for public consumption are my Spanish Flashcards app, refactored so each user has their own flashcards, and a new Interactive Lists app, an expansion of a proof of concept I built using websockets. They're connected with a common layout and a shared authentication layer using Facebook Connect.

The main purpose of building these apps was to learn a complete node.js stack (more on that below) and gain experience coding and troubleshooting node.js apps.

The second purpose was to demonstrate production node.js code to prospective clients. New Leaf Digital is now officially a half-Drupal, half-Node.js shop (and happy to switch more than half to the latter if there is work to be had).

The third purpose (besides using the apps myself) was to allow others to use the apps, as well as to learn from the code. Anyone can login using their Facebook ID and all the code is on Github (under a CC license).

What do the apps do?

Spanish Flashcards lets you create flashcards of English-Spanish word translations. Randomly play your flashcards until you get them all right, and look up new words with the WordReference API.

Interactive Lists lets you create to-do lists, shopping lists, or any other kinds of list, and share your lists with your friends. As you add and remove items from the list, everyone else sees it immediately in real-time. Imagine a scavenger hunt in which everyone is tracking the treasure on their phones, or a family trip to the mall.

Auth (under the hood): a common authentication layer using Facebook Connect, which the other 2 user-facing apps (and the parent app) share.

How they're built

The stack consists of: node.js as the engine, Express for the web framework, Jade for templates, Mongoose for MongoDB modeling, socket.io for real-time two-way communication, everyauth + mongoose-auth for 3rd party authentication, connect-mongodb for session storage, async for readable control flow, underscore for language add-ons, http-proxy for a flexible router. Plus connect-less and Bootstrap for aesthetics. Forever keeps it running.

To bring the 4 apps (parent/HQ, auth, flashcards, lists) together, there were a few options: a parent app proxying to child apps running independently; virtual hosts (requiring separate DNS records); or using Connect/Express's "mounting" capability. Mounted apps were the most complex option, but offered the best opportunity to learn the deep innards of Express, and the proxy solution was unclear at the time, so I went with mounted apps.

Along the way I refactored constantly and hit brick walls dozens of times. In the end it all works (so far!), and the code makes sense. Since the parent app is a whole standalone server hogging its port, I added a thin proxy on top which points the subdomain to the app, keeping other subdomains on port 80 open for the future.

The app mounting functionality of Express.js is incredibly robust: using the same app.use() syntax as middleware, you can app.use(anotherApp), or even app.use('/path', anotherApp) to load a whole app at a sub-path. (Then the sub-app's routes all change relative to that "mount point".)

Of course in practice, mounting multiple apps is extremely complex. It's also not the most stable approach: a fatal error in any part of the suite will bring down the whole thing. So on a suite of "real" production apps, I wouldn't necessarily recommend the mounting model, but it's useful to understand. And when it works, it's very elegant.

Coming soon

Over the next few weeks, I'll be writing a series of blog posts about specific lessons learned from building these apps. In the meantime, I hope some people make good use of them, and please report bugs if you find any.

Next I'm going to write about Why Node.js? - why you, perhaps a potential client, or perhaps another developer, should consider building your next app in Node.

Jan 14 '12 3:55pm

How to install xhprof on OSX (Snow Leopard or Lion) and XAMPP

XHProf is a very neat PHP profiler. Documentation and general installation instructions are not hard to come by, but none of the examples I found had the right steps for my particular setup, Mac OSX Lion with XAMPP running php 5.3. (Should apply also to OSX Snow Leopard.) So this post fills in that hole; for everything else regarding xhprof look elsewhere.

The problem is the "architecture" that xhprof compiles to; OSX and xhprof are 64-bit but XAMPP is apparently 32-bit. (If you're using MAMP instead of XAMPP, you'll have a similar problem; here is a solution for that.)

After trying multiple variations, the solution that worked was adapted from this memcached-on-xampp post):

  1. Download the latest copy of xhprof
  2. sudo phpize (not sure if this is actually necessary. You may run into problems here; find the solution to that elsewhere.)
  3. If you've been trying other methods that failed, clean up the old junk: sudo make clean
  4. The most important part:
    sudo MACOSX_DEPLOYMENT_TARGET=10.6 CFLAGS='-O3 -fno-common -arch i386 -arch x86_64' LDFLAGS='-O3 -arch i386 -arch x86_64' CXXFLAGS='-O3 -fno-common -arch i386 -arch x86_64' ./configure --with-php-config=/Applications/XAMPP/xamppfiles/bin/php-config-5.3.1
  5. sudo make
  6. sudo make install
  7. Add to your php.ini:
    xhprof
    extension = xhprof.so
    xhprof.output_dir = "/Applications/XAMPP/xhprof-logs"

Then run php -i | grep xhprof and if it worked, it should tell you which version you're running. If it fails, it will say, xhprof.so: mach-o, but wrong architecture in Unknown on line 0.

Good luck!

Update: It's worth mentioning, you'll probably also need to install Graphviz so xhprof can find the dot utility to generate graphics.

Dec 14 '11 4:53pm

Unconventional unit testing in Drupal 6 with PhpUnit, upal, and Jenkins

Unit testing in Drupal using the standard SimpleTest approach has long been one of my pain points with Drupal apps. The main obstacle was setting up a realistic test "sandbox": The SimpleTest module builds a virtual site with a temporary database (within the existing database), from scratch, for every test suite. To accurately test the complex interactions of a real application, you need dozens of modules enabled in the sandbox, and installing all their database schemas takes a long time. If your site's components are exported to Features, the tests gain another level of complexity. You could have the test turn on every module that's enabled on the real site, but then each suite takes 10 minutes to run. And that still isn't enough; you also need settings from the variables table, content types real nodes and users, etc.

So until recently, it came down to the choice: make simple but unrealistic sandboxes that tested minutia but not the big-picture interactions; or build massive sandboxes for each test that made the testing workflow impossible. After weeks of trying to get a SimpleTest environment working on a Drupal 6 application with a lot of custom code, and dozens of hours debugging the tests or the sandbox setups rather than building new functionality, I couldn't justify the time investment, and shelved the whole effort.

Then Moshe Weizman pointed me to his alternate upal project, which aims to bring the PHPUnit testing framework to Drupal, with backwards compatibility for SimpleTest assertions, but not the baggage of SimpleTest's Drupal implementation. Moshe recently introduced upal as a proposed testing framework for Drupal 8, especially for core. Separately, a few weeks ago, I started using upal for a different purpose: as a unit testing framework for custom applications in Drupal 6.

I forked the Github repo, started a backport to D6 (copying from SimpleTest-6 where upal was identical to SimpleTest-7), and fixed some of the holes. More importantly, I'm taking a very different approach to the testing sandbox: I've set up an entirely separate test site, copied wholesale from the dev site (which itself is copied from the production site). This means:

  • I can visually check the test sandbox at any time, because it runs as a virtualhost just like the dev site.
  • All the modules, settings, users, and content are in place for each test, and don't need to be created or torn down.
  • Rebuilding the sandbox is a single operation (with shell scripts to sync MySql, MongoDB, and files, manually triggered in Jenkins)
  • Cleanup of test-created objects occurs (if desired) on a piecemeal basis in tearDown() - drupalCreateNode() (modified) and drupalVariableSet() (added) optionally undo their changes when the test ends.
  • setUp() is not needed for most tests at all.
  • dumpContentsToFile() (added) replicates SimpleTest's ability to save curl'd files, but on a piecemeal basis in the test code.
  • Tests run fast, and accurately reflect the entirety of the site with all its actual interactions.
  • Tests are run by the Jenkins continuous-integration tool and the results are visible in Jenkins using the JUnit xml format.

How to set it up (with Jenkins, aka Hudson)

(Note: the following are not comprehensive instructions, and assume familiarity with shell scripting and an existing installation of Jenkins.)

  1. Install upal from Moshe's repo (D7) or mine (D6). (Some of the details below I added recently, and apply only to the D6 fork.)
  2. Install PHPUnit. The pear approach is easiest.
  3. Upgrade drush: the notes say, "You currently need 'master' branch of drush after 2011.07.21. Drush 4.6 will be OK - http://drupal.org/node/1105514" - this seems to correspond to the HEAD of the 7.x-4.x branch in the Drush repository.
  4. Set up a webroot, database, virtualhost, DNS, etc for your test sandbox, and any scripts you need to build/sync it.
  5. Configure phpunit.xml. Start with upal's readme, then (D6/fork only) add DUMP_DIR (if wanted), and if HTTP authentication to the test site is needed, UPAL_HTTP_USER and UPAL_HTTP_PASS. In my version I've split the DrupalTestCase class to its own file, and renamed drupal_test_case.php to upal.php, so rename the "bootstrap" parameter accordingly. ** (note: the upal notes say it must run at a URL ending in /upal - this is no longer necessary with this approach.)
  6. PHPUnit expects the files to be named .php rather than .test - however if you explicitly call an individual .test file (rather than traversing a directory, the approach I took), it might work. You can also remove the getInfo() functions from your SimpleTests, as they don't do anything anymore.
  7. If Jenkins is on a different server than the test site (as in my case), make sure Jenkins can SSH over.
  8. To use dumpContentsToFile() or the XML results, you'll want a dump directory (set in phpunit.xml), and your test script should wipe the directory before each run, and rsync the files to the build workspace afterwards.
  9. To convert PHPUnit's JUnit output to the format Jenkins understands, you'll need the xUnit plugin for Jenkins. Then point the Jenkins job to read the XML file (after rsync'ing if running remotely). [Note: the last 3 steps have to be done with SimpleTest and Jenkins too.]
  10. Code any wrapper scripts around the above steps as needed.
  11. Write some tests! (Consult the PHPUnit documentation.)
  12. Run the tests!

Some issues I ran into (which you might also run into)

  1. PHPUnit, unlike SimpleTest, stops a test function after the first failure. This isn't a bug, it's expected behavior, even with --stop-on-failure disabled. I'd prefer it the other way, but that's how it is.
  2. Make sure your test site - like any dev site - does not send any outbound mail to customers, run unnecessary feed imports, or otherwise perform operations not meant for a non-production site.
  3. In my case, Jenkins takes 15 minutes to restart (after installing xUnit for example). I don't know why, but keep an eye on the Jenkins log if it's taking you a while too.
  4. Also in my case, Jenkins runs behind an Apache reverse-proxy; in that case when Jenkins restarts, it's usually necessary to restart Apache, or else it gets stuck thinking the proxy endpoint is down.
  5. I ran into a bug with Jenkins stopping its shell script commands arbitrarily before the end. I worked around it by moving the whole job to a shell script on the Jenkins server (which in turn delegates to a script on the test/dev server).

There is a pending pull request to pull some of the fixes and changes I made back into the original repo. In the pull request I've tried to separate what are merely fixes from what goes with the different test-site approach I've taken, but it's still a tricky merge. Feel free to help there, or make your own fork with a separate test site for D7.

I now have a working test environment with PHPUnit and upal, with all of the tests I wrote months ago working again (minus their enormous setUp() functions), and I've started writing tests for new code going forward. Success!

(If you are looking for a professional implementation of any of the above, please contact me.)

Recent related post: Making sense of Varnish caching rules

Dec 12 '11 3:52pm

Making sense of Varnish caching rules

Varnish is a reverse-proxy cache that allows a site with a heavy backend (such as a Drupal site) and mostly consistent content to handle very high traffic load. The “cache” part refers to Varnish storing the entire output of a page in its memory, and the “reverse proxy” part means it functions as its own server, sitting in front of Apache and passing requests back to Apache only when necessary.

One of the challenges with implementing Varnish, however, is the complex “VCL” protocol it uses to process requests with custom logic. The syntax is unusual, the documentation relies heavily on complex examples, and there don’t seem to be any books or other comprehensive resources on the software. A recent link on the project site to Varnish Training is just a pitch for a paid course. Searching more specifically for Drupal + Varnish will bring up many good results - including Lullabot’s fantastic tutorial from April, and older examples for Mercury - but the latest stable release is now 3.x and many of the examples (written for 2.x) don’t work as written anymore. So it takes a lot of trial and error to get it all working.

I’ve been running Varnish on AntiquesNearMe.com, partly to keep our hosting costs down by getting more power out of less [virtual] hardware. A side benefit is the site’s ability to respond very nicely if the backend Apache server ever goes down. They’re on separate VPS's (connected via internal private networking), and if the Apache server completely explodes from memory overload, or I simply need to upgrade a server-related package, Varnish will display a themed “We’re down for a little while” message.

But it wasn’t until recently that I got Varnish’s primary function, caching, really tuned. I spent several days under the hood recently, and while I don’t want to rehash what’s already been well covered in Lullabot’s tutorial, here are some other things I learned:

Check syntax before restarting

After you update your VCL, you need to restart Varnish - using sudo /etc/init.d/varnish restart for instance - for the changes to take effect. If you have a syntax error, however, this will take down your site. So check the syntax first (change the path to your VCL as needed):
varnishd -C -f /etc/varnish/default.vcl > /dev/null

If there are errors, it will display them; if not, it shows nothing. Use that as a visual check before restarting. (Unfortunately the exit code of that command is always 0, so you can’t do check-then-restart as simply as check-varnish-syntax && /etc/init.d/varnish restart, but you could grep the output for the words “exit 1” to accomplish the same.)

Logging

The std.log function allows you to generate arbitrary messages about Varnish’s processing. Add import std; at the top of your VCL file, and then std.log("DEV: some useful message") anywhere you want. The “DEV” prefix is an arbitrary way of differentiating your logs from all the others. So you can then run in the shell, varnishlog | grep "DEV" and watch only the information you’ve chosen to see.

How I use this:
- At the top of vcl_recv() I put std.log("DEV: Request to URL: " + req.url);, to put all the other logs in context.
- When I pipe back to apache, I put std.log("DEV: piping " + req.url + " straight back to apache"); before the return (pipe);
- On blocked URLs (cron, install), the same
- On static files (images, JS, CSS), I put std.log("DEV: Always caching " + req.url);
- To understand all the regex madness going on with cookies, I log req.http.Cookie at every step to see what’s changed.

Plug some of these in, check the syntax, restart Varnish, run varnishlog|grep PREFIX as above, and watch as you hit a bunch of URLs in your browser. Varnish’s internal logic will quickly start making more sense.

Watch Varnish work with your browser

Varnish headers in Chrome Inspector
The Chrome/Safari Inspector and Firebug show the headers for every request made on a page. With Varnish running, look at the Response Headers for one of them: you’ll see “Via: Varnish” if the page was processed through Varnish, or “Server:Apache” if it went through Apache. (Using Chrome, for instance, login to your Drupal site and the page should load via Apache (assuming you see page elements not available to anonymous users), then open an Incognito window and it should run through Varnish.)

Add hit/miss headers

  • When a page is supposed to be cached (not pipe'd immediately), Varnish checks if there is an existing hit or miss. To watch this in your Inspector, use this logic:
sub vcl_deliver {
  std.log("DEV: Hits on " + req.url + ": " + obj.hits);
 
  if (obj.hits > 0) {
    set resp.http.X-Varnish-Cache = "HIT";
  }
  else {
    set resp.http.X-Varnish-Cache = "MISS";
  }
 
  return (deliver);
}

Then you can clear the caches, hit a page (using the browser technique above), see “via Varnish” and a MISS, hit it again, see a HIT (or not), and know if everything is working.

Clear Varnish when aggregated CSS+JS are rebuilt

If you have CSS/JS aggregation enabled (as recommended), your HTML source will reference long hash-string files. Varnish caches that HTML with the hash string. If you clear only those caches (“requisites” via Admin Menu or cc css+js via Drush), Varnish will still have the old references, but the files will have been deleted. Not good. You could simply never use that operation again, but that’s a little silly.

The heavy-handed solution I came up with (I welcome alternatives) is to wipe the Varnish cache when CSS+JS resets. That operation is not hook-able, however, so you have to patch core. In common.js, _drupal_flush_css_js(), add:

if (module_exists('varnish') && function_exists('varnish_purge_all_pages')) {
  varnish_purge_all_pages();
}

This still keeps Memcache and other in-Drupal caches intact, avoiding an unnecessary “clear all caches” operation, but makes sure Varnish doesn’t point to dead files. (You could take it a step further and purge only URLs that are Drupal-generated and not static; if you figure out the regex for that, please share.)

Per-page cookie logic

On AntiquesNearMe.com we have a cookie that remembers the last location you searched, which makes for a nicer UX. That cookie gets added to Varnish’s page “hash” and (correctly) bypasses the cache on pages that take that cookie into account. The cookie is not relevant to the rest of the site, however, so it should be ignored in those cases. How to handle this?

There are two ways to handle cookies in Varnish: strip cookies you know you don’t want, as in this old Pressflow example, or leave only the cookies you know you do want, as in Lullabot’s example. Each strategy has its pros and cons and works on its own, but it’s not advisable to combine them. I’m using Lullabot’s technique on this site, so to deal with the location cookie, I use if-else logic: if the cookie is available but not needed (determined by regex like req.url !~ "PATTERN" || ...), then strip it; otherwise keep it. If the cookie logic you need is more varied but still linear, you could create a series of elsif statements to handle all the use cases. (Just make sure to roast a huge pot of coffee first.)

Useful add-ons to varnish.module

  • Added watchdog('varnish', ...) commands in varnish.module on cache-clearing operations, so I could look at the logs and spot problems.
  • Added a block to varnish.module with a “Purge this page” button for each URL, shown only for admins. (I saw this in an Akamai module and it made a lot of sense to copy. I’d be happy to post a patch if others want this.)
  • The Expire offers plug-n-play intelligence to selectively clear Varnish URLs only when necessary (clearing a landing page of blog posts only if a blog post is modified, for example.) Much better than the default behavior of aggressive clearing “just in case”.

I hope this helps people adopt Varnish. I am also available via my consulting business New Leaf Digital for paid implementation, strategic advice, or support for Varnish-aided sites.

Nov 29 '11 1:06pm

Parse Drupal watchdog logs in syslog (using node.js script)

Drupal has the option of outputting its watchdog logs to syslog, the file-based core Unix logging mechanism. The log in most cases lives at /var/log/messages, and Drupal's logs get mixed in with all the others, so you need to cat /var/log/messages | grep drupal to filter.

But then you still have a big text file that's hard to parse. This is probably a "solved problem" many times over, but recently I had to parse the file specifically for 404'd URLs, and decided to do it (partly out of convenience but mostly to learn how) using Node.js (as a scripting language). Javascript is much easier than Bash at simple text parsing.

I put the code in a Gist, node.js script to parse Drupal logs in linux syslog (and find distinct 404'd URLs). The last few lines of URL filtering can be changed to any other specific use case you might have for reading the logs out of syslog. (This could also be used for reading non-Drupal syslogs, but the mapping applies keys like "URL" which wouldn't apply then.)

Note the comment at the top: to run it you'll need node.js and 2 NPM modules as dependencies. Then take your filtered log (using the greg method above) and pass it as a parameter, and read the output on screen or output with > to another file.

Nov 25 '11 11:59am

Migrating a static 960.gs grid to a responsive, semantic grid with LessCSS

The layout of Antiques Near Me (a startup I co-founded) has long been built using the sturdy 960.gs grid system (implemented in Drupal 6 using the Clean base theme). Grids are very helpful: They allow layouts to be created quickly; they allow elements to be fit into layouts easily; they keep dimensions consistent; they look clean. But they have a major drawback that always bothered me: the grid-X classes that determine an element's width are in the HTML. That mixes up markup/content and layout/style, which should ideally be completely separated between the HTML and CSS.

The rigidity of an in-markup grid becomes especially apparent when trying to implement "responsive" design principles. I'm not a designer, but the basic idea of responsive design for the web, as I understand it, is that a site's layout should adapt automagically to the device it's viewed in. For a nice mobile experience, for example, rather than create a separate mobile site - which I always thought was a poor use of resources, duplicating the content-generating backend - the same HTML can be used with @media queries in the CSS to make the layout look "native".

(I've put together some useful links on Responsive Design and @media queries using Delicious. The best implementation of a responsive layout that I've seen is on the site of FourKitchens.)

Besides the 960 grid, I was using LessCSS to generate my styles: it supports variables, mix-ins, nested styles, etc; it generally makes stylesheet coding much more intuitive. So for a while the thought simmered, why not move the static 960 grid into Less (using mixins), and apply the equivalent of grid-X classes directly in the CSS? Then I read this article in Smashing on The Semantic Grid System, which prescribed pretty much the same thing - using Less with a library called Semantic.gs - and I realized it was time to actually make it happen.

To make the transition, I forked semantic.gs and made some modifications: I added .alpha and .omega mixins (to cancel out side margins); for nested styles, I ditched semantic.gs's .row() approach (which seems to be buggy anyway) and created a .nested-column mixin instead. I added clear:both to the .clearfix mixin (seemed to make sense, though maybe there was a reason it wasn't already in).

To maintain the 960.gs dimensions and classes (as an intermediary step), I made a transitional-960gs.less stylesheet with these rules: @columns: 16; @column-width: 40; @gutter-width: 20;. Then I made equivalents of the .grid_X classes (as Clean's implementation had them) with an s_ prefix:

.s_container, .s_container_16 {
  margin-left: auto;
  margin-right: auto;
  width: @total-width;
  .clearfix();
}
.s_grid_1 {
  .column(1);
}
.s_grid_2 {
  .column(2);
}
...
.s_grid_16 {
  .column(16);
}

The s_grid_X classes were purely transitional: they allowed me to do a search-and-replace from grid_ to s_grid_ and remove the 960.gs stylesheet, before migrating all the styles into semantic equivalents. Once that was done, the s_grid_ classes could be removed.

960.gs and semantic.gs also implement their columns a little differently, one with padding and the other with margins, so what was actually a 1000px-wide layout with 960.gs became a 960px layout with semantic.gs. To compensate for this, I made a wrapper mixin applied to all the top-level wrappers:

.wide-wrapper {
  .s_container;
  padding-right: 20px;
  padding-left: 20px;
  .clearfix();
}

With the groundwork laid, I went through all the grid_/s_grid_ classes in use and replaced them with purely in-CSS semantic mixins. So if a block had a grid class before, now it only had a semantic ID or class, with the grid mixins applied to that selector.

Once the primary layout was replicated, I could make it "respond" to @media queries, using a responsive.less sheet. For example:

/* iPad in portrait, or any screen below 1000px */
@media only screen and (max-device-width: 1024px) and (orientation: portrait), screen and (max-width: 999px) {
  ...
}
 
/* very narrow browser, or iPhone -- note that <1000px styles above will apply here too! 
note: iPhone in portrait is 320px wide, in landscape is 480px wide */
@media only screen and (max-device-width: 480px), only screen and (-webkit-min-device-pixel-ratio: 2), screen and (max-width: 499px) {
  ...
}
 
/* iPhone - portrait */
@media only screen and (max-device-width: 480px) and (max-width: 320px) {
  ...
}

Some vitals tools for the process:

  • Less.app (for Mac), or even better, the new CodeKit by the same author compiles and minifies the Less files instantly, so the HTML can refer to normal CSS files.
  • The iOS Simulator (part of XCode) and Android Emulator (with the Android SDK), to simulate how your responsive styles work on different devices. (Getting these set up is a project in itself).
  • To understand what various screen dimensions looked like, I added a simple viewport debugger to show the screen size in the corner of the page (written as a Drupal6/jQuery document-ready "behavior"; fills a #viewport-size element put separately in the template):
    Drupal.behaviors.viewportSize = function() {
      if (!$('#viewport-size').size()) return;
     
      Drupal.fillViewportSize = function() {
        $('#viewport-size').text( $(window).width() + 'x' + $(window).height() )
          .css('top', $('#admin-menu').height());
      };
      Drupal.fillViewportSize();
      $(window).bind('resize', function(event){
        Drupal.fillViewportSize();
      });  
    };

After three days of work, the layout is now entirely semantic, and the 960.gs stylesheet is gone. On a wide-screen monitor it looks exactly the same as before, but it now adapts to narrower screen sizes (you can see this by shrinking the window's width), and has special styles for iPad and iPhone (portrait and landscape), and was confirmed to work on a popular Android tablet. It'll be a continuing work in progress, but the experience is now much better on small devices, and the groundwork is laid for future tweaks or redesigns.

There are some downsides to this approach worth considering:

  • Mobile devices still load the full CSS and HTML needed for the "desktop" layout, even if not all the elements are shown. This is a problem for performance.
  • The stylesheets are enormous with all the mixins, compounding the previous issue. I haven't examined in depth how much of a problem this actually is, but I'll need to at some point.
  • The contents of the page can only change as much as the stylesheets allow. The order of elements can't change (unless their visible order can be manipulated with CSS floats).

To mitigate these and modify the actual content on mobile devices - to reduce the performance overhead, load smaller images, or put less HTML on the page - would probably require backend modifications that detect the user agent (perhaps using Browscap). I've been avoiding that approach until now, but with most of the work done on the CSS side, a hybrid backend solution is probably the next logical step. (For the images, Responsive Images could also help on the client side.)

See the new layout at work, and my links on responsive design. I'm curious to hear what other people do to solve these issues.

Added: It appears the javascript analog to media queries is media query lists, which are event-able. And here's an approach with media queries and CSS transition events.

Nov 25 '11 11:30am
Tags

Generate pager (previous/next) links for an old Blogspot blog using Node.js

I have an old Blogspot blog that still gets a lot of traffic, but it was very hard to navigate without links from post to post. The template uses an old version of their templating language, and doesn’t have any tags available to generate pager links within Blogger.

So I wrote a node app called Blogger Pager (code on Github) to generate the links, loaded client-side via AJAX.


How it works

  1. Export your blog from Blogspot using the Export functionality. You’ll get a big XML file.
  2. Check out this code on a server with node.js installed.
  3. Put the exported XML file into the root of this app, as blog-export.xml; or change the path in app.js.
  4. Run the app (node app.js, or with forever).
  5. The module in posts.js will parse the XML file and generate an in-memory array of all the post URLs and titles. (Uses the xml2js library, after trying 3 others that didn’t work as well/easily.)
  6. The module in server.js will respond to HTTP requests (by default on port 3003, set in server.js):
    • /pager handles JSONP requests with a ?url parameter, returning a JSON object of the surrounding posts.
    • /posts returns an HTML page of all the parsed posts.
  7. The client-side script depends on jQuery, so make sure your blog template is loading that:
    • e.g. &lt;script src='//ajax.googleapis.com/ajax/libs/jquery/1.X.X/jquery.min.js' /&gt;
  8. In your blog template, load the client-side script in this app, exposed at /js/blog-pager-client.js.
  9. Change the URL (var url…) in the client-side script to the URL of your node app.
  10. Save the template, load a post page. (To debug, comment out the return in bloggerPagerLog() and open the browser console.)
  11. Customize the generated HTML in the client-side addPagerForPost() function or style with CSS.


Known Limitations

  1. Only works with a blog export; if your blog is still getting new content, this won’t read the RSS.


Enjoy!
https://github.com/newleafdigital/blogger_pager

Oct 30 '11 7:21pm

Tilt, 3D Dom Inspector for Firefox

HTML pages appear in the browser in 2 dimensions, but there are actually 2 additional dimensions to the DOM: the hierarchy of elements, and the z-index. A new DOM inspector for Firefox called Tilt displays the DOM in 3 dimensions, showing the hierarchy of elements (not sure about the z-index). This is what the homepage of AntiquesNearMe.com looks like in 3D. Pretty cool.

Oct 30 '11 6:42pm
Tags

Great list of new dev tools from Smashing Magazine

Here's a really superb list of "coding tools and javascript libraries for web developers" from Smashing Magazine. Some of the ones I'll be playing with in the next few days:

  • Tilt, Firefox DOM inspection in 3D.

  • Money.js, an open source API and JS library for currency exchange rates (the code on this will also be good for improving my Node.js techniques)

  • Bootstrap development toolkit

  • IE VMs - might cover more versions of the evil browser than the VirtualBox I use now.

  • a bunch of remote debuggers for mobile, haven't tried them yet

  • Less App - I've been using this one for a long time

  • Has.js - test your JS environment for available constructs.

and a whole bunch of others. After reading that post, I also added Smashing Magazine to my RSS reader.

Oct 16 '11 9:24pm

Exploring the node.js frontier

I have spent much of the last few weeks learning and coding in Node.js, and I'd like to share some of my impressions and lessons-learned for others starting out. If you're not familiar yet, Node.js is a framework for building server-side applications with asynchronous javascript. It's only two years old, but already has a vast ecosystem of plug-in "modules" and higher-level frameworks built on top of it.

My first application is a simple web app for learning Spanish using flashcards. The code is open on Github. The app utilizes basic CRUD (Create-Retrieve-Update-Delete) functionality (of "Words" in this case), form handling, authentication, input validation, and an end-user interface - i.e. the basic components of a web app. I'm using MongoDB for the database and Express.js (which sites on top of Connect, on top of Node) as the web framework. For templating I learned Jade, and for easier CSS I'm using LessCSS.

In the process of building it, I encountered numerous challenges and questions, some solved and many still open; found some great resources; and started to train my brain to think of server-side code asynchronously.

Node is a blank slate

Node "out of the box" isn't a web server like Apache; it's more of a language, like Ruby. You start with a blank slate, on top of which you can code a daemon, an IRC server, a process manager, or a blog - there's no automatic handling of virtualhosts, requests, responses, webroots, or any of the components that a LAMP stack (for example) assumes you want. The node community is building infrastructural components that can be dropped in, and I expect that the more I delve into the ecosystem, the more familiar I'll become with those components. At its core, however, Node is simply an API for asynchronous I/O methods.

No more linear flow

I'm used to coding in PHP, which involves linear instructions, each of them "blocking." Take this linear pseudocode snippet for CRUD operations on a "word" object, for example:

if (new word) {
  render an empty form
}
else if (editing existing word) {
  load the word
  populate the form
  render the form
}
else if (deleting existing word) {
  delete the word
  redirect back to list
}

This is easy to do with "blocking" code. Functions return values, discrete input-output functions can be reused in multiple situations, the returned values can be evaluated, each step follows from the previous one. This is convenient but limits performance: in a high-traffic PHP-MySql application, this flow takes up a server process, and if the database is responding slowly under the load, the whole process waits; concurrent processes quickly hog all the server's memory, and a bottleneck in one part of the stack stalls the whole application. In node, the rest of the operations in the "event loop" continue to run, waiting patiently for the database (or any other I/O) callback to respond.

Coding that way is not so easy, however. If you try to load the word, for instance, you run the query with an asynchronous callback. There is no return statement on the query function. The rest of the code has be nested inside that callback, or else the code will keep running and will never get the response. So that bit would look more like this:

load the word ( function(word) {
  populate the form
  render the form
});

But deeply nested code isn't as intuitive as linear code, and it can make function portability very difficult. Suppose you have to run 10 database queries to populate the form - nesting them all inside each other gets very messy, and what if the logic needs to be more conditional, requiring a different nesting order in different cases?

There are ways of handling these problems, of course, but I'm just starting to learn them. In the case of the simple "load the word" scenario, Express offers the app.param construct, which parses parameters in the URL before executing the route callback. So the :word token tells the app to load a word with a given ID into the request object, then it renders the form.

No more ignoring POST and GET

In PHP, if there's a form on a page, the same piece of code processes the page whether its HTTP method is POST or GET. The $_REQUEST array even combines their parameters. Express doesn't like that, however - there is an app.all() construct that ignores the method, but the framework seems to prefer separate app.get() and app.post() routing. (There's apparently some controversy/confusion over the additional method PUT, but I steered clear of that for now.)

Back to the "word form" scenario: I load the form with GET, but submit the form with POST. That's two routes with essentially duplicate code. I could simply save an entry on POST, or render the form with GET - but what if I want to validate the form, then it needs to render the form when a POST fails validation - so it quickly becomes a mess. Express offers some solutions for this - res.redirect('back') goes back to the previous URL - but that seems like a hack that doesn't suit every situation. You can see how I handled this here, but I haven't yet figured out the best general approach to this problem.

New code needs a restart

In a PHP application, you can edit or deploy the code directly to the webroot, and as soon as it's saved, the next request uses it. With node, however, the javascript is loaded into memory when the app is run using the node command, and it runs the same code until the application is restarted. In its simplest use, this involves a Ctrl+C to stop and node app.js to restart. There are several pitfalls here:

  • Sessions (and any other in-app memory items) are lost every time you restart. So anyone using your app is suddenly logged out. For sessions, this is resolved with a database or other external session store; I can imagine other scenarios where this would be more challenging.
  • An uncaught runtime bug can crash the app, and if it's running autonomously on a server, there's nothing built-in to keep it running. One approach to this is a process manager; I'm using forever, which was built especially for node, to keep processes running and restart them easily when I deploy new code. Others have built tools within Node that abstract an individual app's process through a separate process-managing app.

When should the database connect?

Node's architectural philosophy suggests that nothing should be loaded until it's needed. A database connection might not be needed on an empty form, for instance - so it makes sense to open a database connection per request, and only when needed. I tried this approach first, using a "route middleware" function to connect on certain requests, and separated the database handling into its own module. That failed when I wanted to keep track of session IDs with MongoDB (using connect-mongo) - because a database connection is then needed on every request, and the examples all opened a connection at the top of the app, in the global scope. I switched to the latter approach, but I'm not sure which way is better.

Javascript can get very complicated

  • As logic flows through nested callbacks, variable scope is constantly changing. var and this have to be watched very carefully.
  • Writing functions that work portably across use cases without simple return statements is tricky. (One nice Node convention that covers many of these scenarios is the callback(error, result) concept, allowing calling functions to know if the result came back successfully in a standard way.)
  • Passing logic flow across node's "modules" is also tricky. Closures are helpful here, passing the app object to route modules, for instance. But in many cases, it wasn't clear how to divide the code in a way that was simultaneously logical, preserved variable scope, and worked portably with callbacks.
  • Everything - functions, arrays, classes - is an object. Class inheritance is done by instantiating another class/object and then modifying the new object's prototype. The same object can have the equivalent of "static" functions (by assigning them directly to the object) or instantiated methods (by assigning them to prototype). It's easy to get confused.
  • Javascript is a little clunky with handling empty values. The standard approach still seems to be if (typeof x == "undefined") which, at the very least, is a lot of code to express if (x). I used Underscore.js to help with this and other basic object manipulation shortcuts.
  • Because Express processes the request until there's a clear end to the response, and because everything is asynchronous, it's easy to miss a scenario in the flow where something unpredictable happens, no response is sent, and the client/user's browser simply hangs waiting for a response. I don't know if this is bad on the node side - the hanging request probably uses very little resources, since it's not actively doing anything - but it means the code has to handle a lot of possible error scenarios. Unlike in blocking code, you can't just put a catch-all else at the end of the flow to handle the unknown.

What my Flashcards app does now

The Spanish Flashcards app currently allows words (with English, Spanish, and part of speech) to be entered, shown in a list, put into groups, and randomly cycled with only one side shown, as a flashcard quiz.
The app also integrates with the WordReference API to lookup a new word and enter it - however, as of now, there's a bug in the English-Spanish API that prevents definitions from being returned. So I tested it using the English-French dictionary, and hope they'll fix the Spanish one soon.
It's built now to require login, with a single password set in a plain-text config.js file.

Next Steps for the app

I'd like to build out the flashcard game piece, so it remembers what words have been played, lets the player indicate if he got the answer right or wrong, and prioritizes previously-wrong or unseen words over ones that the player already knows.

Where I want to go with Node.js

I've been working primarily with Drupal for several years, and I want to diversify for a number of reasons: I've become very frustrated with the direction of Drupal core development, and don't want all my eggs in that basket. Web applications are increasingly requiring real-time, high-concurrency, noSQL infrastructure, which Node is well-suited for and my LAMP/Drupal skillset is not. And maybe most importantly, I find the whole architecture of Node to be fascinating and exciting, and the open-source ecosystem around it is growing organically, extremely fast, and seemingly without top-down direction.

Some resources that helped me

(All of these and many more are in my node.js tag on Delicious.)

  • Nodejitsu docs - tutorials on conventions and some best practices.
  • Victor Kane's node introand Lit app, which taught me a lot about CRUD best practices.
  • The API documentation for node.js, connect, and express.js.
  • HowToNode - seems like a generally good node resource/blog.
  • NPM, the Node Package Manager, is critical for sharing portable components, and serves as a central directory of Node modules.
  • 2009 talk by Ryan Dahl, the creator of Node.js, introducing the framework.
  • Forms and express-form, two libraries for handling form rendering and/or validation. (I tried the former and decided not to use it, but they try to simplify a very basic problem.)

Check out the code for my Spanish Flashcards app, and if you're into Node yourself and want to learn more of it together, drop me a line!

Aug 21 '11 4:02pm

Brainstorming: Building an advertising system for AntiquesNearMe.com

One of our first revenue-generating features for Antiques Near Me (a startup antique sale-finding portal which I co-founded) is basic sponsorship ads, which we've simply been calling "featured listings." On the Boston portal, for example, the featured listing would be an antiques business in Boston, displayed prominently, clearly a sponsor, but organic (not a spammy banner ad).

I've been brainstorming how to build it, and the options span quite a range. I'll lay out some of my considerations:

  • The primary stack running the site is Drupal 6 in LAMP, cached behind Varnish to prevent server-side bottlenecks. We could build the whole system in Drupal, with Drupal-based ecommerce to sell it, and render the ads as part of the page. But if advertisers want to see stats (e.g. how many impressions/clicks has their sponsorship generated), a server-side approach has no single place to track impressions.
  • The ad placement logic doesn't have to be fancy - we want the sponsorships to be exclusive for a given time period - so we don't need all the fancy math of DFP or OpenX for figuring out what ad to place where. But the system will eventually need to handle variable pricing, variable time frames, potential "inventory" to check for availability, and other basic needs of an ad system.
  • We're running AdSense ads through Google's free DFP service, so we could set up placements and ad units for each sponsor there. But that's a manual process, and we want the ad "real estate" to scale (eventually for each city and antiques category); so in the long-run it has to be automated. That requires DFP API integration. I've signed up for access to that API, and the PHP library looks robust, but the approval process is opaque, and I'm not sure this is the right approach.
  • A hybrid Drupal-DFP approach, with flexible ad placements in DFP and client-side variables passed in from Drupal to differentiate the stats, sounds nice. But it's not clear if this is feasible; information I've gotten from a big-biz AdOps guy suggests it's not with the free edition.
  • I could build a scalable, in-house, back-end solution using Node.js and MongoDB. In theory this can handle a lot more concurrent traffic (each request being very small and quick) than Drupal/LAMP. Mongo is already in use on the site and I've wanted to learn Node for a while. This would require learning Node well enough to deploy this comfortably; with a custom bridge between Drupal (still handling the UI and transactions) and Node. This could take a while to roll out, and adds another moving piece to an already complex stack.
  • Maybe there's another 3rd party off-the-shelf service to handle this, that could be easily bridged with Drupal?

I'm curious how other sites handle similar requirements. Any ideas?

Aug 16 '11 12:03am

Launched: KickinKitchen.TV, a kids' cooking show

Yesterday we (New Leaf Digital) launched the new site for KickinKitchen.TV, a brilliant new kids' cooking show. The site (designed by another firm) is built on Drupal 7, and invites kids to interact with the show by sharing recipes, photos and videos, entering contests, and spreading the word about the show and healthy eating on social networks.

On the technical side, the site involved a robust content architecture, access rules allowing editors and users to share content creation, COPPA compliance for the young audience, new Mailchimp-Profile2 integration for real-time tracking of content submissions, and some fun jQuery animations.

I got my start programming from the BASIC page in 3-2-1 Contact magazine as a child, and I love to cook, so I think the mission of this show is vital, and I look forward to seeing the website empower those goals.

Aug 10 '11 4:06pm
Tags

Mac shell trick: have Growl notify you when something happens

Let's say you're waiting for some event to happen, and that event is detectable in your unix terminal. Examples: a DNS record to propagate (use ping and grep), a blog post to appear in an aggregator (curl and grep), etc. Instead of checking it every minute, you can have your terminal run a loop until it finds the condition you've set, and when it does, it'll notify you with Growl.

I'll use the DNS-test example here:

To check if domain.com is mapped to 1.2.3.4, we can run,
ping -c1 domain.com | grep "1.2.3.4"; echo $?

Or to check for the appearance of some HTML on a web page, we can do,
curl -s http://somesite.com | grep "some content"; echo $?

The $? at the end checks the exit code - 0 being success, non-0 being error.

Now put that in a loop, running every 30 seconds, with a growl popup when it succeeds:

while true; do
  FOUND=`ping -c1 domain.com | grep "1.2.3.4"; echo $?`; 
  if [[ "$FOUND" -eq "0" ]]; then growlnotify -t "Alert" -m "FOUND" -s; break; fi; 
  sleep 30; 
done

Or in one line,
while true; do FOUND=`ping -c1 domain.com | grep "1.2.3.4"; echo $?`; if [[ "$FOUND" -eq "0" ]]; then growlnotify -t "Alert" -m "FOUND" -s; break; fi; sleep 30; done

Aug 10 '11 3:23pm
Tags

Drupal’s increasing complexity is becoming a turnoff for developers

I’ve been developing custom applications with Drupal for three years, a little with 4.7 and 5, primarily with 6, and lately more with 7. Lately I’ve become concerned with the trend in Drupal’s code base toward increasing complexity, which I believe is becoming a danger to Drupal’s adoption.

In general when writing code, a solution can solve the current scenario in front of us right now, or it can try to account for future scenarios in advance. I’ve seen this referred to as N-case or N+1 development. N-case code is efficient, but not robust; N+1 code is abstract and complex, and theoretically allows for an economy of scale, allowing more to be done with less code/work. In practice, it also shifts the burden: as non-developers want the code to accommodate more use cases, the developers write more code, with more complexity and abstraction.

Suppose you want to record a date with a form and save it to a database. You’d need an HTML form, a timestamp (integer) field in your schema, and a few lines of code. Throw in a stable jQuery date popup widget and you have more code but not much more complexity. Or you could imagine every possible date permutation, all theoretically accessible to non-developers, and you end up with the 14,673 lines in Drupal’s Date module.

Drupal is primarily a content management system, not simply a framework for efficient development, so it needs to account for the myriad use cases of non-developer site builders. This calls for abstracting everything into user interfaces, which takes a lot of code. However, there needs to be a countervailing force in the development process, pushing back against increasing abstraction (in the name of end-user simplicity) for the sake of preserving underlying simplicity. In other words, there is an inherent tension in Drupal (like any big software project) between keeping the UI both robust and simple, and keeping the code robust and simple - and increasingly Drupal, rather than trying to maintain a balance, has tended to sacrifice the latter.

User interfaces are one form of abstraction; N+infinity APIs - which I’m more concerned with - are another, which particularly increase underlying complexity. Drupal has a legacy code base built with partly outdated assumptions, and developers adding new functionality have to make a choice: rewrite the old code to be more robust but less complex, or add additional abstraction layers on top? The latter takes less time but easily creates a mess. For example: Drupal 7 tries to abstract nodes, user profiles, actions, etc into “entities” and attach fields to any kind of entity. Each of these still has its legacy ID, but now there is an additional layer in between tying these “entity IDs” to their types, and then another layer for “bundles,” which apply to some entity types but not others. The result from a development cycle perspective was a Drupal 7 release that, even delayed a year, lacked components of the Entity system in core (they moved to “contrib”). The result from a systems perspective is an architecture that has too many layers to make sense if it were built from scratch. Why not, for example, have everything be a node? Content as nodes, users as nodes, profiles as nodes, etc. The node table would need to lose legacy columns like “sticky” - they would become fields - and some node types like “user” might need fixed meanings in core. Then three structures get merged into one, and the system gets simpler without compromising flexibility.

I recently tried to programatically use the Activity module - which used to be a simple way to record user activity - and had to “implement” the Entities and Trigger APIs to do it, requiring hundreds of lines of code. I gave up on that approach and instead used the elegant core module Watchdog - which, with a simple custom report pulling from the existing system, produced the same end-user effect as Activity with a tiny fraction of the code and complexity. The fact that Views doesn’t natively generate Watchdog reports and Rules doesn’t report to Watchdog as an action says a lot, I think, about the way Drupal has developed over the last few years.

On a Drupal 7 site I’m building now, I’ve worked with the Node API, Fields API, Entities API, Form API, Activity API, Rules API, Token API... I could have also worked with the Schema, Views, Exportables, Features, and Batch APIs, and on and on. The best definition I’ve heard for an API (I believe by Larry Garfield at Drupalcon Chicago) is “ the wall between 2 systems.” In a very real way, rather than feeling open and flexible, Drupal’s code base increasingly feels like it’s erecting barriers and fighting with itself. When it’s necessary to write so much code for so many APIs to accomplish simple tasks, the framework is no longer developer-friendly. The irony is, the premise of that same Drupalcon talk was the ways APIs create “power and flexibility” - but that power has come at great cost to the developer experience.

I’m aware of all these APIs under the hood because I’ve seen them develop for a few years. But how is someone new to Drupal supposed to learn all this? (They could start with the Definitive Guide to Drupal 7, which sounds like a massive tome.) Greater abstraction and complexity lead to a steeper learning curve. Debugging Drupal - which requires “wrapping your head” around its architecture - has become a Herculean task. Good developer documentation is scarce because it takes so much time to explain something so complex.

There is a cycle: the code gets bigger and harder to understand; the bugs get more use-case-specific and harder to nail down; the issue queues get bloated; the developers have less time to devote to code quality improvement and big-picture architecture decisions. But someone wants all those use cases handled, so the code gets bigger and bigger and harder to understand... as of this writing, Drupal core has 9166 open issues, the Date module has 813, Rules has 494. Queues that big need a staff of dozens to manage effectively, and even if those resources existed, the business case for devoting them can’t be easy to make. The challenge here is not simply in maintaining our work; it’s in building projects from the get-go that aren’t so complicated as to need endless maintenance.

Some other examples of excessive complexity and abstraction in Drupal 7:

  • Field Tokens. This worked in Drupal 6 with contrib modules; to date with Drupal 7, this can’t be done. The APIs driving all these separate systems have gotten so complex, that either no one knows how to do this anymore, or the architecture doesn’t allow it.
  • The Media module was supposed to be an uber-abstracted API for handling audio, video, photos, etc. As of a few weeks ago, basic YouTube and Vimeo integration didn’t work. The parts of Media that did work (sponsored largely by Acquia) didn’t conform to long-standing Drupal standards. Fortunately there were workarounds for the site I was building, but their existence is a testament to the unrealistic ambition and excessive complexity of the master project.
  • The Render API, intended to increase flexibility, has compounded the old problem in Drupal of business logic being spread out all over the place. The point in the flow where structured data gets rendered into HTML strings isn’t standardized, so knowing how to modify one type of output doesn’t help with modifying another. (Recently I tried to modify a date_select field at the code level to show the date parts in a different order - as someone else tried to do a year ago - and gave up after hours. The solution ended up being in the UI - so the end-user was given code-free power at the expense of the development experience and overall flexibility.)

Drupal 8 has an “Initiatives” structure for prioritizing effort. I’d like to see a new initiative, Simplification: Drupal 8 should have fewer lines of code, fewer APIs, and fewer database tables than Drupal 7. Every component should be re-justified and eliminated if it duplicates an existing function. And the Drupal 8 contrib space should follow the same principles. I submit that this is more important than any single new feature that can be built, and that if the codebase becomes simpler, adding new features will be easier.

A few examples of places I think are ripe for simplifying:

  • The Form API has too much redundancy. #process handlers are a bear to work with (try altering the #process flow of a date field) and do much the same as #after_build.
  • The render API now has hook_page_build, hook_page_alter, hook_form_alter, hook_preprocess, hook_process, hook_node_views, hook_entity_view, (probably several more for field-level rendering), etc. This makes understanding even a well-architected site built by anyone else an enormous challenge. Somewhere in that mix there’s bound to be unnecessary redundancy.

Usable code isn’t a luxury, it’s critical to attracting and keeping developers in the project. I saw a presentation recently on Rapid Prototyping and it reminded me how far Drupal has come from being able to do anything like that. (I don’t mean the rapid prototype I did of a job listing site - I mean application development, building something new.) The demo included a massive data migration accomplished with 4 lines of javascript in the MongoDB terminal; by comparison, I recently tried to change a dropdown field to a text field (both identical strings in the database) and Drupal told me it couldn’t do that because “the field already had data.”

My own experience is that Drupal is becoming more frustrating and less rewarding to work with. Backend expertise is also harder to learn and find (at the last meetup in Boston, a very large Drupal community, only one other person did freelance custom development). Big firms like Acquia are hiring most of the rest, which is great for Acquia, but skews the product toward enterprise clients, and increases the cost of development for everyone else. If that’s the direction Drupal is headed - a project understood and maintained only by large enterprise vendors, for large enterprise users, giving the end-user enormous power but the developer a migraine - let’s at least make sure we go that way deliberately and with our eyes open. If we want the product to stay usable for newbie developers, or even people with years of experience - and ultimately, if we want the end-user experience to work - then the trend has to be reversed toward a better balance.

Aug 4 '11 2:58pm
Tags

Upgrading to OSX Lion: Some Gotchas

I upgraded my MacBookpro to OSX Lion today. It's $30 in the App Store (or copy the DMG from someone who paid and it's free). ArsTechnica has an extremely comprehensive review of Lion if you want the full details. Here are a few minor hiccups I ran into:

• Custom symlinks in /usr/bin were removed. So far I've noticed the symlink for Git missing (/usr/bin/git -> /usr/local/git/bin/git), I put it back. (There's also a StackExchange thread about this.)

• The AFP protocol on my ReadyNAS - which I was using, among other things, for Time Machine backups - is not compatible with Lion. Fortunately the Netgear folks are quick and have a new beta release with the new protocol; I installed that it seems to be working fine.

• I turned off the new mobile-inspired "natural" scrolling. It doesn't feel natural to me, and I don't want to get disoriented every time I use someone else's computer.

• The new (also mobile-inspired) bouncy scrolling is slightly annoying too, but I can't figure out how to disable that.

• The OS seems to handle memory much better. I'm running all the usual apps, but it's turning a lot more of the "active" RAM (yellow in Activity Monitor) into "free" (green) RAM. I'm not sure what the overall performance impact is yet, but it's nice to see the OS [apparently] cleaning up dead memory better than before.

• Some of the startup items in my user account were removed, I put them back.

Otherwise it's been pretty smooth. I like the new Spaces+Exposé hybrid called Mission Control. One of the main reasons I upgraded so quickly was the new full-disk encryption built in, which I'll set up as soon as I can reboot.

Aug 2 '11 10:51am
Tags

Drupal 7 / Drush tip: Find all field content using a text format

I'm working on a Drupal 7 site and decided one of the text formats ("input formats" in D6) was redundant. So I disabled it, and was warned that "any content stored with that format will not be displayed." How do I know what content is using that format? This little shell snippet told me:

drush sql-query "show tables like 'field_data_%'" | tail -n+2 | while read TABLE; do
  FIELD=`drush sql-query "show fields in $TABLE like '%format%';" | tail -n+2 | awk '{ print $1 }'`; 
  echo "$TABLE - $FIELD";
    if [[ "$FIELD" != "" ]]; then
     drush sql-query "select * from ${TABLE} where ${FIELD}='old_format''";
    fi
done

You'll need to run that in the terminal from your site's webroot and have Drush installed. Rename old_format to the code name of your text format. (drush sql-query "select * from {filter_format}" will show you that.) It'll work as a single command if you copy and paste it (as multiple lines or with line breaks stripped - the semi-colons indicate the end of each statement).

Breaking it down:

  1. Find all the tables used for content storage.
  2. Find all the 'format' fields in those tables. (They'll only exist if the field uses formats.)
  3. Find all the rows in those tables matching the format you want to delete. Alternatively, if you want everything to be in one format, you can see what does not use that format by changing the ${FIELD}=... condition to ${FIELD}<>'new_format'.

This won't fix anything for you, it'll just show you where to go - look at the entity_id columns (that's the nid if the content is nodes) and go edit that content.

Also note, this is checking the field_data_ tables, which (as far as I can tell) track the latest revision. If you are using content revisions you might want to change the first query to show tables like 'field_revision_%'. I'm not sure why D7 duplicates so much data, but that's for another post.

Update: I modified the title from Find all content to Find all field content because of the comment by David Rothstein below.

May 18 '11 11:48pm
Tags

Workaround to variables cache bug in Drupal 6

I run my Drupal crons with Drush and Jenkins, and have been running into a race condition frequently where it tells me, Attempting to re-run cron while it is already running, and fails to run.

That error is triggered when the cron_semaphore variable is found. It's set when cron starts, and is deleted when cron ends, so if it's still there, cron is presumably still running. Except it wasn't really - the logs show the previous crons ended successfully.

I dug into it a little further: drush vget cron_semaphore brought up the timestamp value of the last cron, like it was still set. But querying the `variables` table directly for cron_semaphore brought up nothing! That tipped me off to the problem - it was caching the variables array for too long.

Searching the issue brought up a bunch of posts acknowledging the issue, and suggesting that people clear their whole cache to fix it. I care about performance on the site in question, so clearing the whole cache every 15 minutes to run cron is not an option.

The underlying solution to the problem is very complex, and the subject of several ongoing Drupal.org threads:

Following Drupal core dev policy now (which is foolish IMHO), if this bug is resolved, it has to be resolved first in 8.x (which won't be released for another 2-3 years), then 7.x, then 6.x. So waiting for that to work for my D6 site in production isn't feasible.

As a stopgap, I have Jenkins clear only the 'variables' cache entry before running cron:
drush php-eval "cache_clear_all('variables', 'cache');"

That seems to fix the immediate problem of cron not running. It's not ideal, but at least it doesn't clear the entire site cache every 15 minutes.