20 Feb 2013

jQuery.Deferred() is pretty easy

I was using an asynchronous file uploader and, for usability, wanted to make sure the upload progress bar was displayed for at least a couple seconds before changing the view. The jQuery.Deferred object made this a breeze, eliminating a bunch of callback/isDone checking mess:

var uploadFinished = $.Deferred(),
    timerFinished = $.Deferred();
$.when(uploadFinished, timerFinished).done(function () {
    changeView();
});

// immediately after starting upload
setTimeout(timerFinished.resolve, 2000);

// in upload completed event handler
uploadFinished.resolve();

The docs make the Deferred object a little more complicated than it really is. You don’t have to have to alter processes to return Deferred/Promise objects, you can just make them and pass them around as needed in a pinch.

19 Feb 2013

“If You’re Feeling Sinister” Documentary!

12 Feb 2013

Shared Server Development with PhpStorm

Working on a remote server—with or without multiple developers—is just asking for problems, but sometimes there’s no way around this. I’ve used several IDEs for this task and found that PhpStorm has several unique features that ease the pain considerably:

  • It fingerprints remote content on download and re-verifies the remote content before auto-uploading. If someone else has edited that file, you get an option to merge/download/cancel. If the merge has conflicts you get a nice diff view to make manual decisions.
  • It can check the server whenever you open a file. That way you can known right away remote changes have occurred before working.
  • It keeps a history of all file changes and lets you revert to any or merge content from any of them into the current version. Even if you git commit frequently, this is a huge help sometimes. A coworker had accidentally overwritten one of the files I had recently changed and added his own code. When I realized this I just popped open Local History and merged my changes into the current file with a single click.
  • It can generate a diff with remote over a file/directory tree. You then can decide per file whether to upload/download/delete/leave as is.
  • It can auto-deploy changes made outside the IDE. I can set it so while PhpStorm is open, anything done to my local cache files (e.g. git checkout/some other operation) is deployed to remote.

PhpStorm basically nails remote development like it does most other areas.

Why not work on via remote file system (e.g. samba/sshfs)? With basic text editors you can kinda get away with this, but a true IDE needs to watch a lot of files, and if they’re remote…

Why not use an IDE on the remote server? I don’t know of any text-based IDE. Extremely good code editors, sure, but that difference matters.

31 Dec 2012

Sparks “Sherlock Holmes”

The jam.

30 Dec 2012

Cannabis criminalization helps law enforcement (perform unconstitutional searches)

Opponents of cannabis decriminalization often state we should keep it criminalized in order to help law enforcement catch bad guys, and indeed it serves as an important tool for justifying searches on individuals and premises. After all, these searches may turn up more harmful criminal activities or individuals with warrants. LEO’s will often admit that in many cases they are not really after the pot and may even ignore the offense if no other offenses are found.

From a public safety standpoint, allowing “I smelled marijuana” to serve as probable cause for search may on net improve safety, but we should reject this notion because these searches are basically unconstitutional. Cannabis use, after all, is not what most officers are really after; it’s a justification.

The Fourth Amendment was not created by accident; the power to search without cause can and often is abused by LEOs, and the especially militarized flavor of drug raids in the U.S. is often needlessly violent and deadly.

When cannabis is no longer criminalized, yes, searching individuals based on a hunch (without real cause) will be harder—the goal of the Bill of Rights was not to make policing easy—but consider if we had never criminalized cannabis and it had at least as many users as it currently does. Knowing what we now know about the mild harms of the drug, would we really choose to turn at least several million people into regular criminals in order to give LE the power to search them without cause and occasionally using violent SWAT raids?

No we would not and should not. If anything this “LE tool” argument is a reason to decriminalize.

4 Dec 2012

Designing a Highly Reusable HTML Component

The UF College of Education uses a header/footer template designed to be applied to any page, and we use this across several applications such as WordPressMoodleElgg, and Drupal. Changes can be propagated quickly to all sites, and adding the template to new PHP apps is trivial.

If you need to create an HTML component that can be reused across a wide set of sites/apps, these guidelines might help.

Avoid HTML5 elements if you can

HTML5 elements like header must be accompanied by JS to fix compatibility in old browsers. Sticking to HTML4 also helps with validation under HTML4/XHTML doctypes. Of course, if you’ll only be deploying to HTML5 sites that already have the IE shim, go ahead and use the best markup elements for the job.

Guard the host markup against the component CSS

Any component CSS selectors that match host markup elements can cause massive problems in the host application, and if this component is applied across an entire site, it’s very difficult to predict the impact. The key then is following a few simple rules for the component CSS:

  1. Each class/id name must be sufficiently unique such that there’s practically no chance of name collision. Unfortunately even selectors like .hidden and .clearfix could be implemented in different ways in the host app and this could cause problems. Using a constant prefix in every name might help.
  2. Each selector must include at least one of the component classes/ids.
  3. Avoid using a CSS reset/normalizer. If you must, make sure each selector follows the above rules so the effect of this is limited in scope to the component.
  4. Selectors must not match non-component elements. E.g. the selector #component-root + div should not be used because it would select a DIV element after the component.
  5. Take care to avoid obscuring elements in the host page. E.g. negative margins could pull the component over a host element.

Guard the component markup against the host CSS

Similarly, host CSS could break the desired styling of the component markup.

  • Test the component in a wide variety of pages and applications. Especially test pages that use common CSS resets and normalizers, and that have a lot of element-only selectors in the CSS.
  • When interactions occur, make the affected element’s selector more specific until the component CSS “wins”. As always, test across the browsers you need to support; IE7 still has some specificity bugs for the selectors it understands, if you need to care about that.

Javascript Tips

Expose as little to the global namespace as possible

E.g., define all necessary functions and variables inside an anonymous function that is executed:

!function () {
  // your code here ...

  // explicitly expose an API
  this.myComponentAPI = api;
}();

Document your script’s dependencies and let the implementor supply those

Automatically including JS libraries may break the host app. Consider the case of jQuery: Many plugins extend the jQuery object, so redefining it removes those added functions (actually stores them away, but it will break the host app nonetheless). Don’t assume the user did this right. Wrap your functionality in a condition that first tests for the presence of the the library/specific features you need, and make it easy for the implementer to realize the problem if they have a console open.

Here’s an example of how to test for jQuery’s on function:

if (this.jQuery && jQuery.fn.on) {
  // code
} else if (this.console && console.log) {
  console.log('Requires jQuery.on, added in version 1.7');
}

Assume the component could be embedded after the page loads, and multiple times

Carefully consider the initialization process your component requires. In some cases it’s reasonable to leave the initialization to be triggered by the implementer. If you do automatically use DOMReady functions like jQuery’s ready(), consider allowing the implementer to cancel this and initialize later.

20 Sep 2012

Wedding Mixes: Moose

Moose “This River Never Will Run Dry” [marry in the morning mix]

In this mix:

  • More balanced volume across the song (you can hear the intro without having to turn it down several times later). This is a simple volume envelope, so it didn’t squash the dynamics any more that they were already.
  • Shortened outro without the screeching halt at the end. Yes, some will find this blasphemous. Judge away.
27 Aug 2012

Decouple User and App State From the Session

When building software components, you want them to be usable in any situation, and especially inside other web apps. The user of your component should be able to inject the user ID and other app state without side effects, and similarly be able to pull that state out after use.

That’s why, beyond all the standard advice (GRASP SOLID), you’d be wise to avoid tight coupling with PHP Sessions.

PHP’s native1 session is the worst kind of singleton.

It’s accessible everywhere; modifiable by anyone; and, because there’s no way to get the save handlers, there’s no way to safely close an open session, use it for your own purposes, and reopen it with all the original state. Effectively only one system can use it while it’s open.

The Take Home

  • Provide an API to allow injecting/requesting user and application state into/from your component.
  • Isolate session use in a “state persister” subcomponent that can be swapped out/disabled, ideally at any time during use.

1Shameless plug: I created UserlandSession, as a native session replacement. You can use multiple at the same time, and there’s no global state2 nor visibility. This is not to suggest that you use it in place of native sessions, but it’s available in a pinch or for experimentation.

2Yes, I know cookies and headers are global state. UserlandSession is not meant to solve all your problems, pal.

25 Aug 2012

Elgg Plugin Tip: Make Your Display Queries Extensible With Plugin Hooks

If you’re building an Elgg plugin that executes queries to fetch entities/annotations/etc. for display, odds are someone else will one day need to alter your query, e.g. to change the LIMIT or ORDER BY clauses. Depending on where your query occurs, he/she may have to override a view, replace an action, replace a whole page handler, or have no choice but to alter your plugin code directly. There’s a better way. Read the rest of this entry »

17 Aug 2012

My Moodle Page, Now With 99.6% Fewer Queries

My work recently upgraded from Moodle 1.9 to 2.3, and some users were experiencing slow page loads while the site was zippy for others. Today we discovered that, for some users, the My Moodle dashboard page was requiring several thousands of DB queries. For one user, enrolled in four courses, the page required over 14,000 queries. I guess it could be worse: one user reported over 95,000!

This was completely unacceptable; this page is a common navigation point for all users, and every user is forwarded there on login.

With xdebug and Autosalvage rocking, it only took me about three hours to rework the page so that only the course links are displayed by default, and a button is provided beside each to load that course’s activities into the page via Ajax. Since most users just use the page for navigation between courses, this tradeoff seems well worth the performance gain. Now this page–without displaying activities–is down to ~60 queries for every user (sadly average for a Moodle page).

I suspect that loading the activity list for a large course will still take a performance bite, but in my limited testing it seemed pretty instantaneous–yes, there’s a reason why modern apps are built on Ajax. Although good work has been done to cache front-end files, Moodle still seems to be in serious need of query reduction optimization when building HTML pages.

After getting some feedback over the weekend, I’ll release this patch for other Moodle providers. Our theme uses jQuery and the Javascript side of this was maybe 10 lines, but I imagine it would need to be ported to YUI to get into core.