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.

Saturday, July 19, 2014

Re-Teaching Myself to Read

When I was a kid, I did most things because I was told to.  I was mortally afraid of “getting in trouble.” I didn’t know what trouble entailed, but in my imagination it was a dark pit of shame that you would never escape from.  


Being a “good girl” is a great strategy for excelling at K-12 tasks. Show up on time, speak at appropriate moments, turn in homework that is perfect because your father has already checked it for mistakes. You will get A’s, you will be liked, you will get into college, you will feel superior in some small way to most of the world.


However, once you get beyond the realm of K-12 style education and life gets harder, this strategy is less effective. It doesn’t fail you altogether, you can work harder as the challenges get bigger, but you do start to get the feeling that you’re constantly at the end of your rope, that you’re barely hanging on, that if the challenges move one inch further out, you’d fall off the ledge.    


What happens when the good girl strategy is pushed to its limit? It’s simple, you have to rebuild your life.




For the past year, I have been re-teaching myself to read.  For my entire life I have read the books that I was told to. This includes all the extra credit books. Once books stopped being assigned to me in college, I still read the books that felt the most “respectable” - Joyce, Hemingway, Dickens. Books from boyfriends, and bosses and lists titled “Warren Buffet’s Top 30 Business Books”.  


Not only did I read what they taught me to, I read how they taught me to: one word at a time, reading “aloud” to myself silently without moving my lips, from the first page to the last, never looking back.  I just kept turning pages.  It never occurred to me that there was another way to read.


By some coincidence, I have met three people who read at least twice as fast as me and with considerably higher comprehension.  Meeting one was a fluke, meeting two made me curious, meeting three convinced me I was missing something.


Plus, I was jealous.


I queried them extensively about how they read so fast and so well. The first thing they said was that they don’t read the words aloud to themselves silently.  At first, I was skeptical.  That’s how I was taught to read, surely that’s the only way to do it.  But no!


There are more things in heaven and earth, Horatio,  
Than are dreamt of in your philosophy. 
- Famous play, 12th grade AP Lit.


I went to the internet.  The term for reading aloud to yourself is “subvocalization” and it is how many people are taught to read and how many adults still read. But it isn’t necessary. It is a hard habit to undo. There was no sure-fire method of doing it, but I was filled with excitement of the possibility of there being another way.


I read the entire internet on the topic of “speed reading.” There wasn’t too much that was definitive.  A lot of big promises, an equal number of doubters. Not a lot of evidence.  I wanted to believe, so I took three online speed readingclasses.”


They were full of exercises like this:







I did these for a year.  Sometimes I felt like I was progressing, sometimes I didn’t.  At the one year mark, I thought I had probably made some speed improvements, but I wasn’t making comprehension improvements, but most of all, I was still subvocalizing. I had basically failed.


Then I was depressed all over again.  It turns out the “good girl” strategy of reading instructions and taking classes couldn’t deliver the miracle I was promised. The thought that kept going through my head was “oh fuck.”


I let go of the speed reading thing, and I retreated from the whole experiment.  I went back to my old way of reading, and realized it wasn’t so bad after all.  At least it got the job done.


A few months later, I was waiting around at home, a little bit bored.  I picked up a fantasy novel off the shelf. I decided to try reading it fast, by basically just glancing at the page and trying to “grok” it. This was one of the reading techniques I had read about. I “read” the first chapter. It was short - only 4 pages.  At the end of 4 pages, I admitted to myself that I really didn’t get a damn thing out of it. So I read it again. I understood a little bit more. But I still didn’t get it. So I read it again.


I read the first 4 pages at least 8 times, but the end of the 8th time, I felt like I grokked it.  I didn’t just feel like I’d read it, I really felt like there was nothing else to get from those four pages.  Then I went on to chapter 2.  


When I started Chapter 2, it felt different.  It wasn’t any faster, I wasn’t speed reading.  The difference was that it was fun. More fun than reading had ever been.


I kept reading.  If I ever didn’t totally grok what I was reading, I’d start cyclically reading paragraphs or pages until there was nothing more to get.


Here is a passage I read the most from Terry Pratchett’s Fantasy-Humor novel “Guards! Guards!”.  I must have read this 10 times before moving on:


“And because magic can only loosely be bound, the Library books themselves were more than mere pulped wood and paper.

Raw magic crackled from their spines, earthing itself harmlessly in the copper rails nailed to every shelf for that very purpose. Faint traceries of blue fire crawled across the bookcases and there was a sound, a papery whispering, such as might come from a colony of roosting starlings.  In the silence of the night the books talked to one another.

There was also the sound of somebody snoring.”


The first time I read it, all I got was “books, library, magic, blue fire.”


The second time I read it, all I got was questions: “Earthing itself harmlessly?” huh? “Blue fire crawling?  Fire doesn’t crawl....”


The third time I read it, I was like “‘copper rails’ that’s oddly specific.” “books whispering? Faint traceries? That seems connected somehow…”


The fourth time I read it, I was like “earthing itself… could that be like grounding itself?  In an electrical sense?  Blue fire! Like electricity. Oh! copper! It’s a conductor of electricity! The whispering is like the little noises electricity makes! OH MY GOD! I GET IT!!! IT’S AN EXTENDED METAPHOR!!! The books are communicating with each other via electricity, and they're alive. They can only do that because they’re all grounded and thus connected to one another because they’re all connected to the earth. The electricity is part of the magic that makes them come to life.”


Go ahead.  Reread it.  See if I’m right.


I was so excited! Reading had never felt this good! It was like a puzzle where the author was giving me clues, and my brain was putting them together all by itself.  The more I just let my brain do its thing, the more I would get.  Forcing myself to keep reading page after page was holding me back. I thought I knew how to read, but I didn’t know the first thing about reading. Just like when you read books aloud to someone else, you don’t get it that well, when I was reading them to myself silently I wasn’t getting it that well.


I reread the last line, “There was also the sound of somebody snoring.”  This is a clue! A clue that the author is going to transition to talking about somebody else.  I can swap all this magic-library-book-metaphor out of memory and reset my brain for what’s coming next and start looking for new clues. This is reading!


Now, this is how I try to read all the time.  It’s not speed reading.  It isn’t faster than normal reading.  If anything, it's slower.  But it doesn’t matter.  My problem was never that I didn’t read fast enough, it was that reading wasn’t enjoyable, and so I didn’t do it.  I actually have plenty of time for reading, if I want to.  


There still may be plenty of things I have to learn about reading.  I still subvocalize and the good-girl outlook is still strong inside me. But at least I have proven to myself that in this one case, I had plenty of things to unlearn and it was possible to reteach myself.  There are probably plenty of other things for me to reteach myself. There is an escape from the feeling of being one inch away from falling off the cliff.

Life strategies are like software, you should plan to throw one away.

Friday, July 11, 2014

Who should I blame?

I have helped many students debug their code. Helping students learn is deeply satisfying to me. But, although I enjoy teaching, I have one pet peeve. It usually goes like this:

Student: "My code won't compile.  I think the compiler is broken."
Me: "Really? What happened?"
Student: "I ran my code, and it just spit out a lot of errors, but I know my code is right."
Me: (looks at compiler error, clicks the first link): "I think this function is supposed to return something"
Student: "....oh."
When there is an error, students will blame the compiler, they blame the starter code, they blame anybody but themselves. This irks me because their logic is so obviously wrong: you have been coding for 1 year, GCC has been around forever. What is the probability that it's really the compiler's fault?

I had a change of perspective on this matter. For the first time in a long time I was using Java to complete an assignment. It was a large, computationally intensive program. I was reimplementing collaborative filtering to run on the Netflix challenge. At some point, I ran my code and got this error:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
 at java.util.HashMap.<init>(HashMap.java:209)
 at java.util.LinkedHashMap.<init>(LinkedHashMap.java:181)
This seemed like the worst possible news to me. I bemoaned by problem to another student:
Me: "Oh my God! I broke Java.  I used up all its memory."
Student: "Did you tell it you needed extra memory?"
Me: "Huh?"
Student: "Just type -Xms512M -Xmx1024M"
Me: "...oh."
I was so embarrassed. I'd violated my own pet peeve. You would think I'd have my priors set correctly on the error being my fault, not the compiler's.  I started to wonder, maybe it isn't about priors.

Over the next months, I started to note other ways of blaming a system for things that were really my fault:

  • "%^*##%ing CSS! What an idiotic way of designing a system."
  • "WHITESPACE?! Whitespace CANNOT be a bug. Damn you Python!"
  • "Why do I have to tell you to convert this number to a string. I'm printing it! Can't you figure it out!"


This list became long and I read it many times. Although it was painful to admit, I had to draw a conclusion that most of my time spent "fixing" bugs is actually spent swearing at my bugs.

Faced with the aggregate of all my time wasted in frustration, I decided that I had to change. I didn't want to waste my life swearing at a compiler that couldn't hear me. I decided that regardless of whose fault the bugs were, I had the power to change myself, and I did not have the power to change the compiler. With that insight, I realized what was really going on.

  • I want to find bugs in my code.
  • My limitations have caused these bugs.
  • I need to acknowledge my limitations to find my bugs.
  • I don't acknowledge my limitations because it is painful.
  • The only way forward is to change my attitude toward my limitations.  
  • Therefore, I have to want to find my limitations.
This small change in perspective made a world of difference in my debugging. Debugging was now a learning opportunity rather than a swearing opportunity. In a way, this change of perspective make me smarter.  Ironically, in order to become smarter, I had to stop thinking of myself as smart. I had to acknowledge my limitations and face them.

When students are learning, they blame the compiler simply as an act of self-preservation. Gradually relaxing that need is one of the life lessons that computer science teaches us. 




Wednesday, June 25, 2014

Changing Perspectives while Learning to Program


When I started programming, I was bad at it.  There were two strategies that I used:

  1. Read example code and try to 'understand' it.
  2. Write a massive amount of code, then compile and debug if necessary. 
It was painful. I would read code for hours, locked in a fruitless quest for 'understanding.' I would write an epic poem's worth of code, compile it, then spend an ice age debugging it.

I assumed that as I learned, I would get better at both these techniques.  I assumed that:
  1. I would be able to read code faster and understand it better
  2. I would become a better debugger and spend less time debugging code I'd written.
Strangely, neither of these things happened. I did improve at programming, but not in the linear path that I'd expected. Instead, I improved by having a major change in the way I was approaching the problem. 
A change in perspective is worth 80 IQ points.
-Alan Kay
I had just started web programming and I was trying to figure out how drag and drop was implemented so that I could modify it. Using my old approach of reading example code, I was wading through the JavaScript of the Yahoo User Interface toolkit (YUI). It was long.  It employed design patterns I had never even heard of and 'understanding' it was becoming a nightmare. I read it for 2 days before I got so fed up with reading the long file that I figured, 'why don't I just rip out all the stuff I don't need?'

At that moment, I began my new perspective of programming.  I was no longer just 'understanding' it, I was interacting with it. Moreover, the process of ripping out code forced me to begin a cycle of reading code, interacting with code, and running code.




The next time I wrote my own code, I no longer took the epic poem approach. I came at it from an iterative perspective.  The better I got, the more I learned to be disciplined about testing each new line of code.  As I improved further, I refined my new perspective and started thinking in terms of writing the smallest testable new bit of code.  Only then, did my debugging time decrease.

I contend that it is not possible to simply write less buggy code.  To become a better programmer, we must adopt better processes that lend themselves to overcoming the inherent difficulties of programming.