Saturday, August 23, 2014

Focus in Programming: Laser Focus vs. Soft Focus

As a programmer, I prize focus. Part of becoming a programmer is improving your ability to focus. Why? Because natural levels of human focus are insufficient to find common programming bugs such as a "single equals" in a conditional statement:

if( x = 5 ){
     print ("5")
}

Over time and with great pains, I have learned to hone my focus.  Although it serves me well most of the time, and I have become efficient at finding subtle syntax bugs like single equals, occasionally I run into bugs like this:

While building the application:
client/index.js:217:1: Unexpected token }

=> Your application has errors. Waiting for file change.

I saw the error and my first thought was "Great! The compiler knows exactly where the bug is! Easy peasy!" But then I go and look at line 217 of the file.

There is no line 217.  The last line is 216.

There's only one thought that goes through my head at this point: "Dear Compiler, WHAT THE FUCK?!"

Then my debugging gets stalled.  I look back at the error and confirm it is line 217. I look back at the file and make sure it is really only 216 lines. I double check the file name.  I focus as hard as I can and drill into this bug.

And it goes nowhere.

Although focus is usually the right solution, it is not the right tool to fix this bug.  More accurately, the narrow, laser-beam focus that I have trained myself to do is not the right tool. Instead, I need to consider my depth of field.



Focus in optics has as property called depth of field.  I have recently started modeling my own attention and focus as having this property.  I think of it like this: the concept of focus is not binary (focused or not focused). When choosing to focus, I must also choose what range of distance (or size of problem) I want to see sharply. 

For example, if I want to focus on one leaf in a tree, I use what I call "laser focus". (This is what I do to find the single-equals bug). I often feel intense when I do this. Caffeine helps.



But I can also focus not on a single leaf, but on the entire tree. I call this "soft focus" because I can feel my eye muscles relax and "soften" when I focus this way. Soft focus in not un-focused. It might not help you find the single equals bug, but it is useful for focusing on an entire system. For example, when I want to see how leaves move together in the wind, I use soft focus.  Soft focus lets me focus on the system as a whole rather than precisely tracking all the leaves individually.



Look out the window and try it right now.

For the "line 217" bug, I stop focusing on the line and the "Unexpected token }" message. Instead, I adjust my focus and consider the file as a whole. I think about recent changes I made, I see if I can Ctrl+Z my way back to working code. If I have to, I do a git diff.

In this case, the problem happened to be a missing parenthesis, not a curly brace as the compiler suggested.

function submit(){
 var radioButton = $('input:checked').val();
   var f = Meteor.call('submit', {
     user_id: Meteor.userId(),
     answer: radioButton
   }  ) <--- I FORGOT THIS FUCKER!!!  
}

Perhaps other people have better spidey sense for this type of bug, but I never would have found that bug by looking at the code.

My strategy is to stop using laser focus to drill into the details, and instead, I think about the system as a whole with a softer focus.


Monday, August 4, 2014

Fixing My Knowledge Gaps: Closures

Everybody has gaps in their knowledge.  I am no exception.  The longer those gaps are there, the more painful they are to admit. If you ask a friend, you fear their response is going to be "Oh my god! How did you get through calculus without knowing that addition is commutative!" Searching the web is even worse. If search the web for "addition commutative" you get thick paragraphs of impenetrable definitions.

Despite the potential for  humiliation, I recently asked my friend Greg for help bridging my most embarrassing knowledge gap.  (Not with the commutative property, obviously - everybody knows what that is.) I warned him that I was sensitive about my ignorance, but I pleaded with him, "Please be gentle, I want to understand closures."

I read the Wikipedia page on Closures.  I read two of the top Stack Overflow answers to "what are closures." None of it helped. The Stack Overflow post had a definition that said, 
"a closure is a stack-frame which is not deallocated when the function returns (as if a 'stack-frame' were malloc'ed instead of being on the stack!)"

Maybe it's just me, but when I read things like that, my eyes glaze over, and I understand nothing.

They also had worked examples.  When I read them, I could follow them, but I never felt enlightened.  They were too toy-like and disconnected from reality. 

function startAt(x)
   function incrementBy(y)
       return x + y
   return incrementBy

variable closure1 = startAt(1)
variable closure2 = startAt(5)

And I said, "This example is stupid. It's incrementing numbers in a really fucked up way.  I thought closures were magical. I don't understand the magic, where is it?"

He said, "If you understand this, then I think you already do understand closures." 

I should have been happy, maybe, but at the moment, I felt so much frustration.  If I do understand closures, why don't I feel like I understand closures?  I feel like I never use them and other people are using them.  I don't even know how to use them in a sentence properly, can I "use a closure"? Do I "design" a closure? Do I write a closure?

At this point, we were both frustrated.  No progress had been made.  I rambled angrily about this illusive magic of closures. I almost went so far as to accuse him of not understanding closures if he didn't understand the magic.  Then he asked me,

"Other than that you don't use them. How do you know that you don't understand closures?"

I thought for a moment, and I said I listened to a lecture on JavaScript recently, and I understood everything up until the moment where they had this code.  And they explained it as being a closure:

calc = (function () {
   var num1 = 5 
   var num2 = 6 
   return { 
       set1 : function (x) { num1 = x}, 
       add : function () { 
           alert(num1 + num2) 
       } 
   } 
})() 

calc.set1(7) 
calc.add()


Greg looked at it and said, "There is some syntactic sugar here. They're making a a function and calling it as the same time.  Here is another way to write it:"

createCalc = function () { 
   var num1 = 5 
   var num2 = 6 
   return { 
       set1 : function (x) { num1 = x}, 
       add : function () { 
           alert(num1 + num2) 
       } 
   } 
}
c = createCalc() 
c.set1(7) 
c.add()

I watched him as he removed a the mysterious enclosing parentheses, and inserted the line 
'c = createCalc()'

My mind was blown. 'REALLY?' I asked, in verbal all-caps.

"Yes"

"Well, fuck. I GET THAT! createCalc() is just a function that returns a calculator."

That insecurity had been needling me for so long. I'd been sweeping it under the rug for so long, and it wasn't even about closures.  Our knowledge about our own knowledge is far from perfect. The communication frustration that Greg and I had disappeared after we used a real-world example as a conversational aid.

I calmed down a bit. Realizing that I did have a basic understanding of closures and that I wasn't totally incapable of understanding them made some of my self-respect return.

"Ok, I do understand closures at a basic level.  But I still don't see why they are special."

We talked about whether they are special.  Until "I get the simple examples.  I need a more complicated example.  An example that illustrates that closures are basically necessary, that they are exactly the right design choice for some type of problem."

"Why did they bother to use a closure in the calculator example.  You don't need one.  You could have just used a function that performs the calculation, like this:

calc = function (n, m) {
    return n + m
}
answer = calc(5, 5)

In total exasperation I said, "What would you ever realistically want a closure for?" 

Greg looked at my simple example.  "I can't think of a good example off hand. However, I can tell you the difference between the way they wrote the calculator and the way you wrote it.  They wrote a closure, and a closure has two parts: the function part and the "state" part.  Their example has some state that each calculator that gets created carries around, which is sort of 'invisible'.  Your calc function doesn't have that.

The term "invisible state" triggered something inside me. Box and pointer diagrams bubbled back into my memory.  

"Ah!" I said, "If the calculator needed to keep around some memory of what the last result was, then you'd need a closure.  And that's pretty realistic.  Calculators have a notion of the 'lastResult.' You can press '5 + 5 =', but you can also, just see that 10 is already the 'lastResult' and just say '+ 5 =' and get 15.  

I went and wrote a the state-ful calculator I had envisioned.

createCalc = function () {
    var lastResult = 0
    var setLastResult = function (x) { 
            memory = x
    }
    return {
        addToMemory : function(n){
            var ans = n + memory
            setLastResult(ans)
            return ans
        },
        add : function (n, m) {
            var ans = n + m
            setLastResult(ans)
            return ans
        }
    }
}


c = createCalc()
answer1 = c.add(5,5)              // 5 + 5 = 10
answer2 = c.addToMemory(5)        // 10 + 5 = 15

I showed my new calculator to Greg and explained:

"If you created two different calculators, they'd each have their own separate 'lastResult state.' Is this an example of a closure?"

"Yes."

And suddenly, I understood the magic.  With Greg's blessing of my example, my internal understanding of closures had transformed. It was the transubstantiation of closures, where examples turned into a concept.

Lessons Learned
  1. Examples can aid communication. Rather than get angry and frustrated in the abstract, try being angry and frustrated about an example that externalizes the issue.
  2. Make sure to articulate 'invisible' things.  People tend to assume that "what you see is all there is" (WYSIATI). When Greg explicitly pointed out that the invisible state (the enclosing environment) was a hallmark of closures, I was able to create an example that incorporated that.
  3. Realistic examples sink in better than toy examples.  They give a better sense of when you would actually want to use the concept. That contributed to my feeling of understanding closures, even though I probably did understand them in some sense before.
  4. Confusion can have multiple layers.  My insecurities about not understanding closures lead to me attributing any example containing closures that I didn't understand to be a misunderstanding of closures. 

Even though my knowledge gap was embarassing and painful to fix, I'm glad I did it.  If you're at all inclined to do so, I recommend it.

Let someone debug you.