25Oct

Facebook as a psychic shopping mall

Posted by Elf Sternberg as Uncategorized

I was hanging out with a friend last night and she said, “I think Facebook is designed to distract you. You go in looking for one thing, but oh, hey, there’s this other thing, and what’s Aunt Marsha up to? Eventually you find yourself spending hours on it.”

What she’s describing is the Gruen Transfer, “the moment someone experiences after entering a shopping mall when, surrounded by an intentionally confusing layout, lose track of their original intentions.” You enter saying “I came to buy a coat” and leave “Ooh, shoes! Cameras! Necklaces! Smoothies!” that much poorer.  Modern mall architects deliberately go for this effect; their objective is to keep you inside the mall as long as possible, in order to increase retailer’s opportunities to sell to you.

Facebook appears to have hit a Gruen Transfer state completely by A/B testing, which if you think about it, is exactly what A/B testing of ad-driven sites is intended to do: keep your eyeballs in front of the advertiser’s windows for as long as possible. Facebook has just had more time, more money, and more talent to throw at the issue than anyone else.  The objective remains the same: to distract you from your objectives, to encourage an increase in sales.  Your pleasures and interests don’t enter into it.

This may be why Twitter is “experimenting” with their newsfeed.  A/B testing shows them that they could keep your eyeballs on their interests for much longer; the only question remains how corrupt they want to deviate from their original mission.

Programmer Zef Hemel recently made a confession, aptly titled I Hate Puzzles. In it, he confesses to a deep loathing for the recruitment come-ons that read “Do you love puzzles?” and even more for recruitment ads that are puzzles. He says, eventually, that he and his wife agreed they don’t understand why people do puzzles. “Sure, if you don’t have anything else to do. We had plenty more useful stuff to do.”

And while I enjoy video games, and especially enjoyed the puzzles within the Portal series, in general I avoid the kind of puzzles found on the average bookshelf or in the average game store window display. Not just jigsaw puzzles, but sudoku, crosswords, the whole gamut of paper-and-pencil puzzling that seems to take up some people’s entire commutes.

Zef then says that he doesn’t care much about algorithms. Algorithms aren’t at the heart of programming: design is. Coming up with a syntax, a domain specific language, an API, that reduces the friction between what another developer wants to acheive and the computer’s capability to achieve, are at the heart of almost all that he does.

And he’s absolutely right.

If I want a word puzzle that’ll increase my vocabulary, I’ll write a fucking novel with my thesaurus and my mind open. I’ll delight in solving the puzzle (yes!) of making sure the characters are three-dimensional, the plot is consistent, the foreshadowing is appropriate, the guns on the mantlepieces have all been fired or elided or revealed to be red herrings. I will hope to make someone else’s day sexier, happier, thoughtful, and delightful.

If I want a brain-teaser, I’ll spend my days trying to understand monads, write tools that let users write tests to a database more efficiently, or (my current unreleased project) write my own goddamn programming language. I will solve not just a puzzle, but a problem. I will hope to make someone else’s day easier, more interesting, and more effective.

I won’t write experimental novels, messing with the structure to produce quasi-lyrical novel-like works, although I admire writers who try that. I don’t have to create new algorithms for my programming language; transducers, scope, homoiconicity, Hindley-Milner, pattern-based dispatch and automatic currying are solved problems; I just want to put those puzzling pieces together in my own idiosyncratic way and hope to learn something about how programming languages work as I do, to make myself a better programmer and to give myself tools for the project after that.

I am a novelist who doesn’t do crosswords. I am a programmer who doesn’t enjoy sudoku. And I don’t do those things because I have much more interesting things to do with my grey matter.

New things.

Last night, I went to a coding meet-up where a few of the others were playing a game.  There’s a website called Exercism.IO, where you can download code exercises and submit your answers to a global community of like-minded players.  The others had been at it for a few minutes; I had to take time to install the exercises and begin.  The basic problem, coded in JavaScript, was “Here are seventeen sentences, each marked as being one of four kinds of conversation: statement, question, argument, or silence.  Write a function that successfully matches the expectations of the test case.”

While the others struggled with both regular expressions and multiple if / then / else if ... trees, I went straight for a different solution:

    this.hey = function(input) {
        var tests = [[function(i) { return /^\s*$/.test(i); },                                      "Fine. Be that way!"], 
                     [function(i) { return /[A-Z][A-Z]+.*!$/.test(i) || /^[A-Z\s]+\??$/.test(i); }, "Woah, chill out!"],
                     [function(i) { return /\?$/.test(i);},                                         "Sure."]];
        for(var i = 0, l = tests.length; i < l; i++) {
            if (tests[i][0](input)) return tests[i][1]; };
        return "Whatever."; };

Seven lines. (Yes, my Javascript coding conventions look like Python and Coffee. Whitespace is one of my secret weapons.) Where everyone else had 20-plus lines of comparisons, I went with the brute-force solution. It took four iterations to shake out all the bugs, all 17 tests passed, and it was done.

There are plenty of places where this is silly code; it's basically arbitrary string reduction, and is completely dependent upon the order of the tests, but as the last result says, "Whatever." To me, however, this reduces a lot of if / then statements down to a single if expression in a hand-written map/reduce: map all possible regexes with a single string, returning [String | Nothing], then reduce down to a single memo of the String. But really, this comes down to a basic rule: wherever you have a list of things to do, see if your language has a proper List with which to contain them.

16Jan

Airplane Mode from the Ubuntu Terminal

Posted by Elf Sternberg as Uncategorized

I ride a bus to and from the office every day. While I love Ubuntu, getting a constant barrage of “WiFi Available” popups whenever we pass by a coffee shop is annoying as hell. Digging into the network manager every day is a chore. Solution: A simple command line handler with a memorable name:

#!/bin/bash
MODE='off'
if [[ -n "$1" ]]; then
    MODE='on'
fi
nmcli nm wifi $MODE

Typing airplane will turn off your wi-fi stack; typing airplane off will turn it back on. (Actually, typing airplane four score and seven years ago will turn it back on. Any argument is accepted as turning airplane mode off. Even airplane on.)

07Jan

git wordcount

Posted by Elf Sternberg as Uncategorized

This is an early draft, but I figured you might enjoy taking a look at my latest little toy:

#!/bin/bash

ARG=""

if [ "${1:0:2}" == '-h' ]; then
    HEAD="${1:1}"
    HEAD=${HEAD//h/^}
    ARG=" HEAD$HEAD..HEAD "
fi

REM=`git diff -U $ARG | grep '^-' | sed 's/^-//' | wc -w`
ADD=`git diff -U $ARG | grep '^+' | sed 's/^+//' | wc -w`
DIF=`expr $ADD - $REM`
echo "Word count: $DIF"

As I’m sure I’ve mentioned before, I write award-winning science fiction as well as hack code, and I use emacs for both activities. I’ve always written primarily in what I think of as Usenet mode, with asterisks and underscores for emphasis and bolding, respectively, a mode that has become codified as Markdown. I used to have my own homegrown toolkit for that, but these days I just use the Python version of Markdown instead. I’ve always used a VCS for that, living entirely in GIT almost since the beginning.

I wanted a simple script to tell me my daily progress. This is it. It compares what’s on the filesystem right now to the latest check-in, or, if you pass it the -h option, it will compare the last check-in to the previous check-in. Each additional -h will push the oldest comparison back one commit, so -hhh will compare the last check-in to the one three check-ins ago.

After writing this, I learned about git-sh-setup and --word-diff=porcelain, both of which will find their way into a future version; hopefully soon you’ll be able to say ‘git wc HEAD^^^..HEAD^^’ or similar, and see how productive you were any two days in the past.

16Oct

Now I get mapping and currying…

Posted by Elf Sternberg as Coffeescript, javascript

Okay, so I’m slow to the party.  Forgive me.  I was reading Reginald Braithewaite’s Javascript Allonge and I understood where he was heading long before he got there, and the lightbulbs were going off in my head, and although his technique for getting there was far more verbose than my own, I finally grokked the big point. It’s a classic programmer’s rule of productivity: If you find yourself doing something more than twice, automate it!

We do this all the time with makefiles and functions, but Braithwaite’s book brought the question down to the micro level: If you have to apply the same transformation to three different arrays, or if you have to apply three transformations to the same array, why are you doing it like this:

somenumbers = [....]
squared = somenumbers.map (x) -> x * x
cubed = _somenumbers.map (x) -> x * x * X
halved = somenumbers.map (x) -> x / 2

When you could do this?

somenumbers
toMap = (a) -> (f) -> a.map(f)
[squared, cubed, halved] = [
    ((x) -> x * x), 
    ((x) -> x * x * x), 
    ((x) -> x / 2)].map(toMap(somenumbers))

By creating a function that already has the array to process, and then processing it multiple times, you prevent the emergence of typos in your code caused by repeatedly typing the variable name. And you accurately put the point of your code in the left-hand column once, which is very attractive to me.

This is good stuff, man. And Coffeescript is so much more expressive than Javascript in the same realm. Imagine writing toMap in JS:

function toMap(a) {
    return function toMap(f) {
        return a.map(f);
    }
}

A lot of clutter to express what Coffeescript expresses so cleanly.

I added the following two items to my .emacs file, and they have changed my life:

(defun night-mode ()
  (interactive)
  (color-theme-initialize)
  (color-theme-lawrence)
  (menu-bar-mode -1)
  (scroll-bar-mode -1))

(defun daylight-mode ()
  (interactive)
  (color-theme-initialize)
  (color-theme-emacs-21)
  (menu-bar-mode 1)
  (scroll-bar-mode 1))

Both of these rely on the emacs “color themes” handler, but really, when working late at night when my eyes are tired, green on black seems to have a nice bit of contrast, whereas when working with a lot of light, the more traditional black-on-light-grey works well for me.  By banishing the menu bars and scroll bar, I eliminate further sources of distracting contrast.

Which makes working with Emacs a heck of a lot more pleasant.  I used to issue these commands by hand, but macro-izing them makes switching modes a much happier and more productive experience.

 

26Sep

Be smart. Don’t be clever.

Posted by Elf Sternberg as Uncategorized

At the office, I led a major initiative to create a lovely drag-and-drop manager for a toolkit of pre-packaged views of.  The views had their own complexities; Splunk search views come with the own controls, and the controls are populated by underlying searches, which may in turn be controlled by other controls.  I fumbled around with various design decisions before realizing the obvious.  What I just described was a tree.  I threw out all my fancy analyzers and weird Backbonification stuff, and wrote a tree handler.

It worked perfectly.

Later, I realized that each view dropped onto the screen could be described using the RDFa trio of typeof/about/property, three rarely used HTML attributes that allow any HTML object to have a rough correspondence a database notion of table/row/column, or the object-oriented notion of class/object/field. Instead of doing all my previous, ridiculously hairy code managing the visual layout, I used the HTML5 drag/drop for positioning, some very small Javascript for grid management, and classic event handling to figure out when new views had been dropped in, moved, or deleted, and I let the existing libraries do all the heavy lifting.  Using data attributes to describe the visual state and CURIE for de-obfuscation, I had a nice event-driven system where everything on the page represents every and only those things I cared about.

The lessons learned were fairly straightforward, and classical.  The data structures you learned in university are usually Good Enough; don’t borrow trouble trying to create a hack for performance reasons.  Premature optimization is always the root of evil.  Second, always survey the tools available to you before starting to code.  You’ll be surprise just how little work you actually have to do.  Clever is writing a lot of code to do a lot of stuff; smart is figuring out that you don’t need a lot of code to do a lot of stuff.

Another lesson learned is that purity matters.  In web application design, view every event as a miniature program– it does two things, it transforms your existing data to create a new structure, and then it illustrates that new structure on the page.  Keep those two things as separate as possible, even if you have to go around your framework to do it, and you’ll have a much more testable system when you’re done.

11Sep

The Functional Programming Crock

Posted by Elf Sternberg as Uncategorized

Quick, what’s the difference between these two expressions?

// Javascript

var add21a = function(a) { return a + 21; };

var add21b = (function(b) {
    return function(a) { return b + a };
})(21);

// Coffeescript

add21a = (a) -> a + 21
add21b = ((b) -> (a) -> b + a)(21)

When I first encountered functional programming, I internalized the definition of a pure function: A pure function is one that always returns the same result given the same arguments.  You should always write your code in a transformative way: Given a set of inputs, write the toolchain to unambiguously create a set of outputs and, only then, perform the side-effect of updating your presentation to reflect your result.

It wasn’t until I was knee-deep into a program with a lot of functions-writing-functions that I stopped to ask myself the question posed above.  I was peeling off dozens of functions that, themselves, were created with closures that retained a lot of state, were themselves mapped to various inputs into the system, and were themselves responsible for producing the output.

The magic is that each individual function was pure: it always gave the same result given the same arguments.  But each function itself was created by a pure function that, given the same arguments, produced the same pure function.  So, was the entire result pure?

The answer, apparently, is yes.  The answer to my question above is, there is no difference.

On the one paw, I understand the point being made here: I can reason about my code much more rationally.  The products of each step are smaller, more reasonable, and generally easier to comprehend, so both ensuring that the code is correct, and debugging it, are facilitated by the functional approach.  On the other paw, this approach allows one to create a vast array of functions rather than a large object with a single function and a vast array of data, with the possibility of code sprawl now simply existing in a different form.

I like functional programming.  It fits my brain, as the Python folks say.  But I don’t think we should at all kid ourselves about the complexity of writing software, or the possibility of anti-patterns emerging out of functional programming.  I’d be happy to say that there are fewer anti-patterns in languages like Haskell or Coffeescript, but the ones left behind are much harder to manage, avoid, and debug.

 

I’ve been a Gentoo user for a very long time. But recently, I bought a laptop and rather than wrestle with Gentoo again, I decided to try the much-praised Linux Mint. It just worked, and it allowed me to build my own code and create a full development environment for all the languages I regularly use (C, Python, Node, Java, Clojure), as well as cross-compiling for android development on Eclipse.

I decided I was tired of the breakage and confusion on my desktop. It was out of date, Gentoo wasn’t keeping up, and I wanted something that just worked. I backed up my desktop to the house NAS, which took about a day. I put the Mint 15 DVD into the reader and within an hour it was fully installed, up and running and everything. After I had a working OS, I used apt-get to install two critical pieces of software: screen and openssh.

From my bedroom, I made a list of about 90 things I had to have installed on the desktop. Now that I had ssh and screen, I used the laptop to SSH down to the desktop and open a screen session. In one window, I started a restore of the /home directory; in the other, I sent the list of packages to apt-get. Then I went to bed.

In the morning, my system was (almost) completely ready.

The (almost) problem was that I had two issues. First, I’m old-school; I had to figure out how to disable the oh-so-modern alphabetical sorting on terminals; I want it ASCIIbetical, the way Gnu intended. Second, and more troubling, it was running an older version of Gnome, not the up-to-date version of Maté. I really had liked the Maté I’d seen yesterday. That turned out to be a simple setting.  Some software packages are fairly out of date in the “stable” version, but I soon had happy modern versions of Handbrake and Wine installed.

Other than that, it was completely without angst or trouble. It’s very pretty, responsive, and working. It runs my Windows VirtualBox nicely (necessary for doing IE8 testing), shows all my movies and plays all my music. I haven’t tried out GTKPod, Azureus, or running Windows natively yet.  I haven’t done any major development with the desktop– I’m not working at home with my current job– but so far I’m very happy. This was even more painless than the upgrade from XP to Windows 7.

Recent Comments