Sneak Attack: BigMac Programmers

Moral of the story: Don't do it—don't be that guy. People hate that guy.

Back to flipping out...


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 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.

Results from SICP Exercise 1.1
My Answer Interpreter's Answer
10 10
12 12
8 8
3 3
6 6
(this was sort of a trick question - the interpreter doesn't print anything when it evaluates define expressions)
see above
19 19
#f #f
4 4
16 16
6 6
16 16

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:

    (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:

    (square a)
    (* a a))

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

    (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:

    (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:

      (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

This will result in an infinite loop, because the interpreter will attempt to evaluate p, which is recursive and has no exit conditions
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...