3 Oct 2013

Using BINARY in a MySQL IN Expression

With the default collations in MySQL (e.g. utf8_general_ci), strings will be matched case-insensitively:

WHERE col IN ('IT', 'Ruby') will match “it” and “ruby”.

For case-sensitive matches, each string must be preceded by the keyword BINARY:

WHERE col IN (BINARY 'IT', BINARY 'Ruby')

Caveat: I would guess that BINARY affects the matching of strings with combining characters (same character, different byte representation).

18 Sep 2013

When Reasonable, Return Early

When you have a function or piece of code that must handle several different cases, I find it much better to eliminate special cases using return or throw at the beginning. (“returning early”).

if (!input.isValid()) {
    throw new InvalidInputException();
}

// handle input (20 lines)

Several advantages here:

  1. It frees our mind from worrying about those cases as we read the rest of the function. Programmers, as humans, have limited mental stacks, and if we’re reading a function that must handle several cases, each of those cases must be held in our memory until we see the code that handles them.
  2. It simplifies the remaining code, since it’s handling a smaller set of cases.
  3. It compartmentalizes the code into: “handle special cases, then handle the common case.”
  4. It keeps the code that handles special cases close to the checks for those cases.
  5. The primary piece of code stays at the root indent level.
  6. Diff views stay simple when adding/removing special conditions (it does not introduce big indenting changes across many lines).

In fact there’s (what I consider to be) an anti-pattern that involves checking for special cases early, but instead placing the meat of the function in the if block, followed by an else block to handle the special case:

if (input.isValid()) {

    // handle input (20 lines)

} else {
    throw new InvalidInputException();
}

Notice how the handling of the error can now become separated from the cause of the error, and the meat of the code now must be indented. This anti-pattern gets obviously worse the more conditions you must test for:

if (input1.isValid()) {
    if (input2.isValid()) {
        if (input3.isValid()) {
            if (input4.isValid()) {

                // handle input (20 lines)

            } else {
                throw new InvalidInputException('input4 is bad');
            }
        } else {
            throw new InvalidInputException('input3 is bad');
        }
    } else {
        throw new InvalidInputException('input2 is bad');
    }
} else {
    throw new InvalidInputException('input1 is bad');
}

This code is hard to read, hard to edit, and harder to review when changes occur to the conditions:

  1. The invalid handling code appears in the reverse order that the inputs are checked.
  2. The invalid handling code is very far from the conditions (you have to lean on the IDE to see where the braces line up).
  3. The meat of the function starts off 4 indents over.
  4. Adding/removing validity checks is a huge pain that involves re-indenting a bunch of code.
  5. Change diffs can look really messy as indent levels are changed.

Code with a lot of special cases/conditions probably needs to be refactored to separate validation from the processing of the input.

There are certainly situations where returning early is not an obvious win (hence “when reasonable”). This often happens when you have a return value that contains complex state, or some statements must be executed before every return/throw statement.

13 Sep 2013

Apache mod_cache and mod_rewrite: Danger

I solved a very strange bug today where mod_cache kept returning a particular cached file for seemingly every URL on a site.

After using LogLevel debug, I finally realized that mod_cache does not store content by the request URL, but rather by the final URL after RewriteRules have been processed.

This PHP application was using a common RewriteRule to map most requests to a single script, but the full request URL was not being copied into the rewritten URL (the script was just relying on $_SERVER['REQUEST_URI'] to route the request). The result is mod_cache considered all URLs the same, and it was only by some magic of session cache-busting headers that the app managed to function at all. Internally mod_cache was just churning that single cache file over and over.

The simple fix was to make sure the full URL path ended up in the internal URL:

RewriteRule ^(.*)$  index.php/$1 [L,QSA]

13 Jul 2013

Chords: “Taramasalata” by Eggstone

V)
    Em     C+    C#m    G#m      F#m   A     F    Dm
    2      2     2      2        2     2     2    2

    F#m    B     C#m    A  G#m   C#m   A  B
    2      2     2      1  1     2     1  1

    Em     C+    C#m    G#m      F#m   A     F    Dm
    2      2     2      2        2     2     2    2

    F#m    B     Dm     C#m      G#m   A  B
    2      2     2      2        2     1  1

    Em     C+    C#m    G#m      F#m   A     F    Dm    A
    2      2     2      2        2     2     2    2     8

C)  
    E      B/D#   G#m   F#m   G#m   F#m   C    D
    2      2      2     2     2     2     2    2

    E      B/D#   G#m   F#m   G#m   F#m   C    D
    2      2      2     2     2     2     2    2

    E        C#m7     Amaj9    F#m9
    4        4        4        4

    E        C#m7     Amaj9    F#m9
    4        4        4        4

    E        C#m      F#m7     C    D
    4        4        4        2    2

on YouTube.

12 Jun 2013

Character Encoding Bug of the Day

Today I had one of those bugs that starts out looking simple and keeps going deeper and deeper. Video service Kaltura has a plugin for Moodle, that just stopped working one day (no changes on the server).

  • It’s throwing an exception because an expected element isn’t in the page.
  • Oh, the element’s supposed to be delivered by XHR from the plugin.
  • But the plugin’s code is generating correct markup…
  • Why is Moodle’s function to serialize an array into a JS function call returning null for that markup?
  • json_encode is converting the markup string to null?
  • Because json_encode is choking on invalid UTF-8.
  • Because the markup has a right single quotation encoded in Windows-1252 :(
  • And that string is coming from the Kaltura API.

So over 2 years ago someone named a video player Jim’s Test Player and over the weekend Kaltura’s API started returning that single quote in Windows-1252. We removed the quote from the name and the problem disappeared.

5 Jun 2013

Simpler Masonry + Sortable Working Together

Since jQuery Masonry repositions elements purely by positioning, it does not play well with UI Sortable. People have posted complex solutions to this problem, but this simpler solution worked for me:

  1. Refresh masonry layout on Sortable’s start, change, and stop events
  2. While dragging, remove from the dragged item the class used to indicate it’s a masonry item
var $c = $('#my_container');
$c.masonry({
    itemSelector: '.masonry-item'
});
$c.sortable({
    start: function (e, ui) {
        ui.item.removeClass('masonry-item');
        $c.masonry('reload');
    },
    change: function (e, ui) {
        $c.masonry('reload');
    },
    stop: function (e, ui) {
        ui.item.addClass('masonry-item');
        $c.masonry('reload');
    }
});
10 Mar 2013

GitHub: Please Syntax Highlight New Files

While syntax highlighting diffs in general would be difficult, it would be easy (and super useful) to apply it to new files.

(All I did to create the mockup below was to take the regular file view and apply background #DDFFDD. It could be that easy.)

Diff with syntax highlighting

 

28 Feb 2013

Installing xhprof on XAMPP for OSX Lion

Directions adapted from Ben Buckman.

Download xhprof.

cd path/to/xhprof/.../extension

# If you don't have autoconf... I didn't.
sudo chmod o+w /usr/local/bin  #(brew needs to write a symlink there)
brew install autoconf

sudo /Applications/XAMPP/xamppfiles/bin/phpize

Make sure you have a CLI C compiler. I installed one via XCode.

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

sudo make

sudo make install

sudo nano /Applications/XAMPP/xamppfiles/etc/php.ini

Add these lines to php.ini:

[xhprof]
extension = xhprof.so
xhprof.output_dir = "/Applications/XAMPP/xhprof-logs"

Restart Apache.

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!