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.

03Jul

“Need a wizard…”

Posted by Elf Sternberg as Uncategorized

I know I’ve said this before, but the recruiter calls– and yes, I’m still getting them, despite gainful employment– are still as annoying as ever. I haven’t had to lecture anyone yet, so the recruiters do seem to be getting smarter, but there’s still an air of desperation around the “rock star,” “ninja,” “wizard,” “samurai” and, I kid you not, “graduate of Hogwarts” developer requests.

The thing that irritates me most about them, recently, is that they’re so… ridiculous. Either you can code, or you can’t. You can look a my github and decide that yes, I can code, and yes, I can code in a lot of things. Javascript and Python, mostly, but there’s also a Ruby project, a C++ project, a Clojure project.

Basically, with some significant exceptions (Haskell comes to mind immediately, as does Forth), everything that’s descended from either C or Lisp is within my cognitive grasp. Set-based languages (SQL and its descendants) are a bit of a departure, and my SQL is sophomoric, but it’s much better than the average WordPress developer’s, and that makes me happy. Also: I’m willing to make it better.

And that last part is what’s most important to me. Recently, work has required I dip my toe back into C++, and some Java, and even some Microsoft stuff. And I’ve managed to muddle through.

A good programmer can learn the basics of a programming language in less than a week. It’s not how good you are at the language, it’s how expressive you are with any language in your arsenal. I’m pretty expressive in Javascript and Python, and I could probably be just as expressive in a CLOS like Clojure or a Smalltalk/Algol mashup like Objective C, given a week or so. It will probably take me that long to wrap my head around any project given to me, given the scope of most modern projects. So the idea that you need an “Objective C Wizard NOW” makes me laugh. You just need a good programmer willing to take on your project.

Now, finding one of those… I can’t help you with.

14Jun

SQL from Hell, my left…

Posted by Elf Sternberg as Uncategorized

That horrible SQL statement I posted a few days ago? Ignore it completely. A little learning is a dangerous thing, as evidenced here by the realization that I didn’t need to mix in the narrator_children query except to exclude those things that had parents, giving me a perfect query to find parentless (root) objects. My entire query boils down to this:

WITH RECURSIVE get_all (series_id, title, slug, path, url) AS (
	SELECT narrator_series.id, title, slug, 
	    TO_CHAR(narrator_series.id * 32, '0000000') AS path, 
	    CONCAT('', slug) AS url
		FROM narrator_series
		JOIN narrator_slugs ON narrator_series.slug_id = narrator_slugs.id
		WHERE narrator_series.user_id = 1 AND narrator_slugs.slug = 'aimee' 
		AND narrator_series.id NOT IN (
			SELECT child_id FROM narrator_children 
			WHERE user_id = 1 and type = 'series')
	UNION
	SELECT narrator_series.id, narrator_series.title, narrator_slugs.slug, 
	            CONCAT(get_all.path, '/', TO_CHAR(narrator_children.position, '0000000')) AS path, 
	            CONCAT(get_all.slug, '/', narrator_slugs.slug) AS url
		FROM narrator_series
		JOIN narrator_slugs ON narrator_series.slug_id = narrator_slugs.id
		JOIN narrator_children ON narrator_series.id = narrator_children.child_id
		JOIN get_all ON narrator_children.series_id = get_all.series_id
		WHERE narrator_children.type = 'series' 
	)
(SELECT series_id, title, slug, path, url, 'series' AS type from get_all
UNION
SELECT narrator_stories.id, narrator_stories.title, narrator_slugs.slug, 
        CONCAT(get_all.path, '/', TO_CHAR(narrator_children.position, '0000000')) AS path,
	CONCAT(get_all.url, '/', narrator_slugs.slug) AS url,
	'story' AS type
	FROM narrator_stories
	JOIN narrator_slugs ON narrator_stories.slug_id = narrator_slugs.id
	JOIN narrator_children ON narrator_children.child_id = narrator_stories.id
	JOIN get_all on get_all.series_id = narrator_children.series_id
	WHERE narrator_children.type = 'story') ORDER BY path;

The only problem with this query is that it assumes that the series being asked for is a root series. I want to be able to start from an arbitrary point in the tree, with ascent and decent as needed, but that should come eventually. But grief, that is so much shorter and more readable (and it supplies the URLS!)!

Recent Comments