Real Ultimate Programming

The Home for People Who Like to Flip Out and Write Code

You Didn’t Think I Had Forgotten, Did You?

This is the first post in my long-promised series of follow-up posts to The Education of a Programmer. I must have started this post at least 5 times, and each time I read the first sections of Structure and Interpretation of Computer Programs (SICP). I can’t really come up with words to do it justice—Abelson and the Sussmans describe the core concepts of computer programs in the most concise yet understandable way I’ve ever seen. Since I can’t improve on the original, these posts will just be a sort of running diary as I work through the exercises in the book. And without further ado…

Exercise 1.1

In this exercise, we are asked to manually evaluate each expression as if we were the interpreter.

<table summary="A table comparing my answers to the actual result from the interpreter">
  <caption>Results from <abbr title="Structure and Interpretation of Computer Programs">SICP</abbr> Exercise 1.1</caption>
  <thead>
    <tr>
      <th id="my-answer">My Answer</th>
      <th id="interpreter-result">Interpreter's Answer</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td headers="my-answer"><kbd>10</kbd></td>
      <td headers="interpreter-result"><kbd>10</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>12</kbd></td>
      <td headers="interpreter-result"><kbd>12</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>8</kbd></td>
      <td headers="interpreter-result"><kbd>8</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>3</kbd></td>
      <td headers="interpreter-result"><kbd>3</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>6</kbd></td>
      <td headers="interpreter-result"><kbd>6</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer">(this was sort of a trick question - the interpreter doesn't print anything when it evaluates <code>define</code> expressions)</td>
      <td headers="interpreter-result"></td>
    </tr>
    <tr>
      <td headers="my-answer">see above</td>
      <td headers="interpreter-result"></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>19</kbd></td>
      <td headers="interpreter-result"><kbd>19</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>#f</kbd></td>
      <td headers="interpreter-result"><kbd>#f</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>4</kbd></td>
      <td headers="interpreter-result"><kbd>4</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>16</kbd></td>
      <td headers="interpreter-result"><kbd>16</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>6</kbd></td>
      <td headers="interpreter-result"><kbd>6</kbd></td>
    </tr>
    <tr>
      <td headers="my-answer"><kbd>16</kbd></td>
      <td headers="interpreter-result"><kbd>16</kbd></td>
    </tr>
  </tbody>
</table>

Exercise 1.2

In this exercise, we are asked to convert a mathematical expression into prefix notation.

(/ 
   (+ 5 4 
      (- 2 
         (- 3 
            (+ 6 
               (/ 3 4)))))
   (* 3 
      (- 2 6) 
      (- 2 7)))

Exercise 1.3

In this exercise, we are asked to define a procedure that takes three numbers as parameters and returns the sum of the square of the two largest parameters. If you were starting from scratch, the solution would look something like this:

  (define
    (sum-of-squares-for-two-largest a b c)
    (cond ((and (< a b) (< a c)) (+ (* b b) (* c c)))
          ((and (< b c) (< b c)) (+ (* a a) (* c c)))
          (else (+ (* a a) (* b b)))))

But that’s not very clean. There’s too much repeated logic, and it’s not very readable; we need some abstraction. The most obvious abstraction is to create a square procedure that looks something like this:

  (define
    (square a)
    (* a a))

Using this new procedure, we can rewrite our sum-of-squares-for-two-largest procedure like so:

  (define
    (sum-of-squares-for-two-largest a b c)
    (cond ((and (< a b) (< a c)) (+ (square b) (square c)))
          ((and (< b c) (< b c)) (+ (square a) (square c)))
          (else (+ (square a) (square b)))))

That’s better, but there’s still room for improvement: we can create a sum- of-squares procedure that looks like this:

  (define 
    (sum-of-squares a b) 
    (+ (square a) (square b)))

Look at that: we created the same procedures that the authors walked us through creating earlier this chapter. Using our new sum-of-squares procedure, sum-of-squares-for-two-largest looks like this:

  (define
      (sum-of-squares-for-two-largest a b c)
      (cond ((and (< a b) (< a c)) (sum-of-squares b c))
            ((and (< b c) (< b c)) (sum-of-squares a c))
            (else (sum-of-squares a b))))

Exercise 1.4

In this exercise, we are asked to describe what the following procedure is doing.

  (define (a-plus-abs-b a b)
    ((if (> b 0) + -) a b))

This procedure is summing a and the absolute value of b. The (if (> b 0) + -) tells us that the procedure being applied to the arguments will differ based on whether b is positive or non-positive. When it’s non-positive, b will be subtracted from a, which is functionally equivalent to always adding the absolute value of b to a.

Exercise 1.5

Applicative-order

This will result in an infinite loop, because the interpreter will attempt to evaluate `p`, which is recursive and has no exit conditions Normal-order

This will return 0 because the interpreter will evaluate the `if` before deciding whether to evaluate `p` or return 0, and the results of the `if` will indicate it should return 0

Back to flipping out…

Test Suites as Quality Diodes

Larry O’Brien recently wrote a a post about relative sizes of tests vs. the code they exercise wherein he mentions an interesting concept: tests as quality diodes. For those of you who’ve forgotten how diodes worked, or never learned in the first place (lucky you), here’s a decent introduction to diodes.

The immediate point of the metaphor was obvious - code that passes tests is quality, code that fails tests is not. But once upon a time, I was expected to know about the inner workings of diodes (thanks, ECE 3040), so I’ve taken the metaphor and run with it. To start with, I’ll be comparing entire test suites to a single diode.

Warning: The following paragraphs contain scenes of graphic metaphor- stretching. A metaphor may have been harmed in the writing of this post.

One of the distinguishing characteristics of diodes is known as peak inverse voltage. If the voltage across a diode is going the wrong direction (a situation called reverse bias) and exceeds the diode’s peak inverse voltage, then you get an unpleasant effect known as avalanching. This is pretty similar to what happens when you try to slap a test suite on a lot of traditional applications. Test suites are traditionally expected to be passing most of the time, and the code they exercise is supposed to be more good than bad (or it wouldn’t be passing the tests most of the time). If instead you have more bad code than good, you’ve reverse-biased your quality diode. If there is pressure to get this dev-task done and get back to work—after all, it’s not like you’re adding a feature to the product—then you may have just exceeded your test suite’s peak inverse voltage. The resulting avalanching tends to gut your test suite, either because you stop running it (you already know it will have failures) or because you throw it out entirely (why maintain code that isn’t doing anything for us).

What should we do about a situation like this? In the world of electronics, one solution is the Zener diode. Instead of avalanching, it breaks down in a more controlled fashion, though it usually does so at much lower inverse voltages. We’d like our test suite to exhibit this same resistance to avalanching—a Zener test suite, so to speak.

One way to build a Zener test suite would be to reduce your test coverage. Sure, the first casualty will likely be the code that needs the most help, but some test coverage is better than none, and none is what you wind up with if your test suite starts avalanching. Once you have your Zener test suite in place, you can work on transforming it into a more traditional test suite by slowly increasing the coverage. That’s not entirely accurate, though: if you do it right, your test suite will grow to have the benefits of the classic test suite while retaining the resistance to avalanching of the Zener test suite, and that’s our real goal.

Back to flipping out…

CSV From Oracle

Ever wanted to dump data out of Oracle and into a CSV? Perhaps you needed to export some info to QA or create a chart. Have no fear, there’s a surprisingly straightforward way to do it. I know: Oracle and straightforward don’t appear in the same sentence often, but in this case it really is simple. Just use set colsep , and you’re in business.

Back to flipping out…

How Do You Counter an Acid(3 Test)? With a Base(3 Test)

Lately, the WebKit and Opera devs have been racing to see who can make their browser pass the Acid3 test first, or at least be the first to get 100/100 (for more details on why this is not the same thing, please visit the earlier Wikipedia link). Notably absent from this entertaining contest was Firefox. If you’re saying “Hold on! They’re probably just trying to get Firefox 3 out the door,” you’re right… sort of. While that is supposedly the main argument put forward by shaver in his recent blog post on Acid3, it takes less than 2 paragraphs to completely exhaust that idea and 7 (mostly massive) paragraphs to bag on the Acid3 test for focusing on the wrong things. Meanwhile, Rob Sayre dismisses the test in his blog post on the subject without even offering the excuse (which I believe is totally valid) that Firefox 3 is the top priority. So, since it seems to be the consensus among Firefox devs that Acid3 focused on the wrong things, why don’t they publish a test that they think focuses on the right things? Dan_Farina over at the programming subreddit suggested this “Base3” test and I think he’s right.

Back to flipping out…

JavaScript Idioms - Copying an Array

Ever see a block of JavaScript that looks like this?

var myArray = [];
for (var i = 0; i < source.length; i++) {
    myArray[i] = source[i];
}

That’s the popular way to copy the elements of one array (note the lack of capitalization) into a new Array (note the capitalization - we’ll get to this in a minute). I wasn’t really a fan, at first, but it’s almost as pervasive as

while(*dst++ = *src++);

in C, so eventually I decided to stop worrying and love the bomb. Basically, JavaScript will automatically grow your Array for you, so you can dispense with all the sizing you might expect when using something called an Array.

Now for the notes you took on capitalization. Not everything that acts like an array in JavaScript is actually an Array. One example is the arguments property available to Functions. If you happen to need the stuff in arguments as an actual Array (because you want to use it as a key for a map/dictionary/hash, let’s say), you will find yourself writing some code like that above. Just remember that sometimes stuff is “Array-like” without actually being an Array, because it can really bite you if you’re not careful.

Back to flipping out…

How Do You Balance Different Target Audiences With Different Needs

The Problem

Different groups of your users have different ways of handling the same basic tasks and/or data. Names and addresses are just two of the more common types of data that vary from culture to culture. So how do you handle this situation? The immediate impetus for this post is this proggit comment about names. I can see at least 3 different approaches, each of which has drawbacks.

The Strategies

Ignore the needs of the smaller target audience(s)

This is the one I’ve seen most often in the wild, and I can see it’s appeal: if you are only giving up a few potential users/customers, you’ll probably offset your losses by increasing your saturation in the supported target audience(s). Still, I always get a vague feeling of unease when I knowingly make it harder/impossible for a group of people to use my work.

Limit your functionality to the common subset

I don’t know that I’ve ever encountered this, and I can see why. When you get right down to it, there’s not much about this world that is constant across all places, people, and cultures. That doesn’t leave you a lot of functionality to put into your app. Even when there is a common subset, your different target audiences will probably still prefer to use an application/site that supports the nuances they are used to, and nuances are the first thing to go when you start chopping functionality down to a common subset, pretty much by definition.

Hide the functionality that is subject to change until you know which variant to expose

There are a couple of problems here:

  • You may not even need the information for anything else, and users are famously reluctant to give out personal info. If you do ask them for the information, please keep Application Design Mistake No. 9 in mind.
  • It may not be feasible to hide the functionality in question. If your application/site doesn’t require users to register, for example, then it might be hard to keep track of the information necessary to know which variant of the functionality to expose.

The “Solution”

In reality, I imagine most developers would prefer some mixture of the strategies listed above, though I could be wrong. What does your solution look like?

Back to flipping out…