Book Review: Pragmatic Thinking and Learning

I was planning on reading Andy Hunt’s Pragmatic Thinking and Learning: Refactor Your Wetware for a while, but kept putting it off, thinking it wasn’t really central to what I’m interested in, what I’m doing.  I was wrong.

People have different skill levels, from novice to expert.  One sign of expertise is the ability to intuit solutions not available through linear thinking.  Intuition happens on the right side of the brain, so we need to use the right side more effectively.  Rather than “left brain” and “right brain”, he calls them “L-mode” and “R-mode”, for “linear” and “rich”, to emphasize that it’s not literally two halves of your brain working differently, but two different modes of thinking.  Most of the book is about using R-mode more, and using L-mode appropriately, to fact-check your R-mode.

It draws on psychology, neurobiology, cognition studies, managing, teaching, the arts, product design, and math.  The bibliography is ten pages long, and I’ve got a bunch of them highlighted for my next evening at the bookstore.

The most valuable changes I’ve made since finishing the book are:

– Be ready when your R-mode strikes. Since “querying” the R-mode can take a long time, we run it asynchronously, and we never know when the results will come in.  (This explains the “ah-ha!” moments in the shower, on the drive home, and when you’re falling asleep.)  So keep a notebook handy for writing things down.  I’m writing in a notebook almost daily (I’ve joined the cult of moleskine), writing down ideas as they come up.  It’s also a tider home for all the scraps of paper that have lived in my wallet for years, ideas scrawled and smudged into them.  And I’m on my 4th or 5th pocket mod.

– Maintain your ‘exo-cortex,’ your external memory. I wrote a mini-wiki engine with Sinatra, and so far, I’ve used it for everything from clojure, to saving quotes, to robot rights.  I wrote it for practice, but it’s nice to have a searchable, non-linear notebook.

The book mentions Gerald Weinberg’s fieldstone method of writing: to build a stone wall, you gradually gather stones from the field as you clear it, and pile them up.  When you have enough, build your wall.  Both the wiki and the notebook serve this purpose.

– Map out your thinking, and doodle. Drawing pictures engages your R-mode, making it more active, helping you make connections, and understand more clearly.  Besides, it’s fun. This is my 3rd time learning emacs, and it’s finally sticking — I think it’s mostly because I drew up a cheat-sheet, pictorially explaining each command’s effect.  I also map out my learning and career goals this way.

emacs cheat sheet

One of my favorite parts is, after you’ve mapped something out, and the drawing looks like a pile of yarn, re-draw it on a clean sheet, fixing up all the awkward placements and messy bits.  The benefit of this second version is in its creation — by considering how to re-organize it, you’re thinking more about the problem, in ways you might not have before.  This works for note-taking, too.

– Take advantage of your brain’s plasticity. You can change how your brain works by believing it works differently: make it smarter, more creative, cheerier.  This is a pretty incredible claim, but he cites two books I’d like to check out.  It sounds impossible, but I’ve seen it work on me, to some extent.  My biggest problem is continuing to believe it works.

Some things I have yet to try:

– Take a walk.  A meditative walk, like around a labyrinth.

– Write morning pages: for three weeks, as soon as you wake, write down three pages of text.  It doesn’t have to be anything specific.  The idea is, right after we wake, our R-mode is more active, so the gems will be more accessible, and they’ll pop out onto the page.  I’m more curious to see what I come up with.

– I have to get better at setting SMART goals: specific, measurable, achievable, relevant, and time-boxed.  I’ve never been much for this kind of discipline — I made a few, but didn’t stick to them, and haven’t gotten into the habit yet.  But like the book says, change is hard:

Change is always harder than it looks — that’s a physical reality, not just an aphorism. An old, ingrained habit makes the equivalent of a neural highway in your brain. These old habits don’t go away. You can make new neural highways alongside, going a different route and making short-cuts, but the old highways remain. They are always there for you to revert to—to fall back on. Practice may not make perfect, but it sure makes permanent.

Advertisements

Heading to the Int’l Lisp Conf, 2009

My next step on the road to lisp is at the International Lisp Conference in Cambridge, MA, this March.

A lot of people are surprised to hear I’m interested in Lisp, but I’ve been studying scheme informally for about 3 years, reading SICP, and finishing The Little Schemer last year. I’ve been interested in clojure for about 18 months, especially after seeing Rich Hickey talk about it last March.  Now I’m studying it in earnest with Stu Halloway’s Programming Clojure.

I don’t use lisps of any sort at work, so it’s not a “practical” language to study like, say, C# is.  But that’s short-term thinking.  Learning lisp is plenty practical, if you’re looking longer-term — even if it’s only three years out.  Learning lisp teaches you about some of the core issues of programming.

I like learning lisp because it’s a window into the workings of programming languages, being so close to the AST.  I want to learn more about meta-programming with macros, hygienic or not.

And for the record, the functional techniques in The Little Schemer have improved my Ruby, JavaScript, and C# in some really solid ways. Functional programming is making its way to the rest of the programming world, and lisp does functional programming.

If you’ll be at the conference, I’d love to hear from you.

Passing by reference, and dog leashes

Pass-by-reference and pass-by-value are pretty confusing when you start learning to code. When I first saw them, I know I ignored the distinction (until I got tired of my code not doing what I expected). Throwing collections into the mix just makes it worse.

Today, though, we stumbled on a pretty decent analogy for passing-by-reference: a reference to an object is like a leash to a dog. Let’s take our dog Dagwood for a walk.

Dog dagwood = new Dog(“Dagwood”);

new Dog() creates, of course, a new Dog object. Dog dagwood creates a reference that can point to any Dog object — it’s really the leash, but we name our references for what they point to, rather than what they are: a reference, a handle, a leash. The equals sign takes the leash, and hooks it to Dagwood’s collar. Now we can take Dagwood for a walk.

dagwood.walk();

To tell Dagwood it’s time to walk, we tug on the leash. He feels the tug, and gets the message, so he starts following us. We come to a busy road, and wait for the crossing signal, but Dagwood’s oblivious, and tries to cross anyway.

dagwood.halt();

Since we’re stopped, he feels the tug of the leash again, gets the message, and stops. We’re sending messages to Dagwood through his leash. In OO terms, sending a message to an object means calling one of its methods. We’re calling methods on our Dagwood through our reference to him, through the leash.

Storing a reference in an array

In the park, we find a snack shop. We’re getting hungry, but the snack shop doesn’t let dogs inside. Luckily, there’s a chain link fence, and in our eyes, a chain link fence is nothing but a big row of places for us to attach a dog leash. We tie a spare leash to the end of the fence, and attach it to Dagwood’s collar.

Dog[] fence = new Dog[10]; // only room for 10 dogs
fence[0] = dagwood;

What’s happening here in OO terms is that our reference to Dagwood, our leash, is copied into the zeroth slot on the fence. It’s not our leash, but it’s one just like it. So now there are two leashes on Dagwood: one in our hand, and one on the fence. We’ll take our leash off Dagwood, since we can’t very well hold it while we’re in the store.

dagwood = null;


Don’t worry, he’s fine…he’s still tied to the fence, by that other leash. Let’s go buy cashews.

When we come out of the store, we want to re-attach our leash to Dagwood.

dagwood = fence[0];

Now let’s untie him from the fence, and head over to the lake.

fence[0] = null;

Passing by reference

Passing references to methods works in much the same way. Dagwood got kind of stinky, swimming in the lake, so let’s bring him to the groomer for a bath.

DogGroomer.shampoo(dagwood);

When you pass a reference to a method, your reference is copied into that method. Again, it’s like a new leash, one just like ours, springs into the groomer’s hand — now Dagwood’s attached to us, and the groomer. He gets fidgety when he’s getting bathed, so it’s just as well.

From the groomer’s perspective, it might look like this:

void shampoo(Dog doggie) {
wet(doggie);
apply(shampoo, doggie);
rinse(doggie);
towelDry(doggie);
}

The groomer doesn’t care what Dagwood’s name is, she just keeps calling him “doggie.” That’s ok, she must see a lot of dogs during the day…names aren’t that important to her. The interesting thing is, even though it’s the groomer who’s shampooing our dog, since we still have a leash on him, we can observe him getting cleaner.

When she’s done, the procedure ends, the method returns, and her leash to Dagwood disappears. Which is fine, because he’s stopped fidgeting, now that he’s dry.

Garbage collection

We head back home through the park. Dagwood’s itching to run around, but we’re tired, so we just unleash him. Hopefully we can find him before it gets dark…

dagwood = null;


Unfortunately, the dog catcher spots him running around without a leash, which is illegal in these parts — a stray dog will hang around forever, eating up resources. The dog catcher carries off our poor Dagwood, and destroys him. We take it in stride, and try to keep the whole circle of life allocation-deallocation in mind.

So…

So that’s how references work. It’s why code like this (C#) will ensure the balloon bouquet has at least one balloon that says “Happy Birthday!”:

List balloons = GetBalloons();
Balloon printed = balloons.Find(Balloon.IsPrinted);
if (printed == null) {
printed = new Balloon();
printed.PrintMessage(“Happy Birthday!”);
balloons.Add(printed);
}
return balloons;

Why We Abstract, and What To Do When We Can’t

Whenever you see yourself writing the same thing down more than once, there’s something wrong and you shouldn’t be doing it, and the reason is not because it’s a waste of time to write something down more than once. It’s because there’s some idea here, a very simple idea, which has to do with the Sigma notation…not depending upon what it is I’m adding up. And I would like to be able to always…divide the things up into as many pieces as I can, each of which I understand separately. I would like to understand the way of adding things up, independently of what it is I’m adding up.

– Gerald Sussman, SICP Lecture 2a, “Higher-order Procedures” (emphasis added)

The purpose of abstracting is not to be vague, but to create a new semantic level in which one can be absolutely precise.

– Edsger W. Dijkstra, The Humble Programmer

What Larry Wall said about Perl holds true: “When you say something in a small language, it comes out big. When you say something in a big language, it comes out small.” The same is true for English. The reason that biologist Ernst Haeckel could say “Ontogeny recapitulates phylogeny” in only three words was that he had these powerful words with highly specific meanings at his disposal. We allow inner complexity of the language because it enables us to shift the complexity away from the individual utterance.

– Hal Fulton, The Ruby Way, Introduction (emphasis added)

Programming is our thoughts, and with better ways to express them, we can spend more time thinking them, and less time expressing them.

3 + 3 + 3 + 3 + 3 + 3 is hard…hard to read (how many threes?), hard to get right (I lost count!), hard to reason about (piles of operations!). 3 x 6 is easy, once you learn multiplication. This is a good trade-off. We should look for ways to add abstractions, new semantic levels, to our programs.

If you’re doing the same thing twice, stop, and look for the common idea. Peel the idea away from the context, from the details. Grasp the idea, and then use it over and over. As a bonus, you’ll type less, re-use code, and debug less.

“But I can’t find ways to do that!”

When you look at similar bits of code, and can’t find a good way to remove the duplication, you’re hitting the limits of either your language, or your knowledge.

Programming languages put up very real walls, they force you down their paths, often by leaving out features. A language without recursion puts up a wall in front of recursive solutions; a language without first-class functions makes it tough to write higher-order functions. Language limitations are the cause of Greenspun’s Tenth Rule.

Sometimes, the language is not the problem. Sometimes you just can’t find your way through. This is why you read Refactoring, and Design Patterns, but really, this is why you learn other programming languages. Think about the right way to factor the problem.

If you can’t remove the duplication, you need to work around your language, or learn some new tricks.

Why Functional JavaScript?

I’m teaching myself functional programming (FP). I first noticed it in Ruby, even though it’s been in JavaScript all along. I’m working my way through Structure and Interpretation of Computer Programs (SICP), and The Little Schemer books, so I’m learning Scheme and Lisp too.

When studying FP, I generally use JavaScript and Scheme. My FP examples here are usually in JavaScript:

  • It’s available everywhere, and most programmers are comfortable reading it.
  • It’s closer to Scheme than Ruby is, so the examples translate better. In fact, Douglas Crockford notes: “JavaScript has much in common with Scheme. It is a dynamic language. It has a flexible datatype (arrays) that can easily simulate s-expressions. And most importantly, functions are lambdas. Because of this deep similarity, all of the functions in The Little Schemer can be written in JavaScript.”

I include Ruby or Scheme, though, if it seems appropriate.

I often use the JavaScript Shell, or its big brother, the JavaScript Development environment, because I haven’t found or built a JavaScript REPL as nice as Dr. Scheme.

Performance

Most current JavaScript implementations are slow with recursion and closures…two cornerstones of functional programming.

I don’t worry about this, because my examples are not meant to be dropped into production systems without thought and testing. I write production-ready code at work; here, I play and explore. We do use some functional JavaScript where I work, but it’s where the performance is acceptable, and the imperative alternative would be too unwieldly.

History seems to show that performance is a short-term concern, and better programming techniques are a long-term concern. It also seems that there are no inherent reasons JavaScript is slow; more performant implementations may be in our future.

Why not Haskell or Erlang?

…or OCaml, Scala, F#, Clojure? I’m getting there. SICP and The Little Schemer books are more than enough for me right now.

reCAPTCHA: stop spam. read books.

This is really cool. reCAPTCHA is a free CAPTCHA service that asks the user to type two words. They know the first word, but the second comes from a failed OCR scan. If you get the first word right, reCAPTCHA assumes you’re human, and they store your answer to the second word…they even run it by a few other humans to raise the confidence. Not only are you authenticated, you’re transcribing. According to reCAPTCHA, “in aggregate these little puzzles consume more than 150,000 hours of work each day”.

[For the record, I don’t know anyone at reCAPTCHA. I found them while reading up on CAPTCHAs for work.]

Ruby, Yoga for your Brain

Just a fun little bit of writing, for a contest

LISP has jokingly been described as “the most intelligent way to misuse a computer”. I think that description a great compliment because it transmits the full flavour of liberation: it has assisted a number of our most gifted fellow humans in thinking previously impossible thoughts.

The analysis of the influence that programming languages have on thinking habits of its users, and the recognition that, by now, brainpower is by far our scarcest resource, they together give us a new collection of yardsticks for comparing the relative merits of various programming languages. The competent programmer is fully aware of the strictly limited size of his own skull…

– Edsger W. Dijkstra, The Humble Programmer

“Brainpower is by far our scarcest resource,” indeed. Why then, would I want mine blown? I’d rather gently stretch it. Extend it. Liberate it. Yoga for my brain, please.

In yoga, you honor your body’s suggested threshold of pain. If you can’t do the full posture, don’t hurt yourself, but try this modification, so you still benefit. When you’re ready, you can try the full posture.

Ruby is like yoga for your mind. Ruby encourages you to stretch to your limits, and come back when you’re ready for more. You can write getters and setters, and old-school for loops, and Ruby won’t complain…but it’ll gently encourage you to try attr_reader and attr_writer, and block iteration. You can write your own database access code, until you’re ready to try active record. You can write straight OO, and never leave the Kingdom of Nouns, until you’re ready to try something more functional.

Ruby lets you learn new things, in a familiar setting. With Ruby, you can honor your mind’s suggested threshold of pain. Ruby hasn’t blown my mind, and I trust it never will. A few nasties have blown my mind, and it’s never fun. It takes time to recover from abuse like that. I’d rather follow the yogis out there, and enjoy the benefits of life-long mental flexibility.

Who’s Afraid of Functional Programming?

Joel Spolsky just published a great (and very brief) explanation of functional programming. There’s also a podcast of Berkeley’s CS 61A SICP course from Spring ’06 that I found — the first few lectures on functional programming are really worth your time. And finally, for a rambling, evening-discussion style explanation of functional programming, complete with historical anecdotes, there’s Functional Programming for the Rest of Us. [You might want to save that one, and come back when you have some time…but do come back to it.]

Joel’s article got me thinking. I’m not really working on applications (at work or for fun) that really need massive concurrency, so that benefit of functional programming never swayed me much. Most of the uses I see for functional programming are simple things, like the selector filters I wrote about in Hacking the Browser’s DOM for Fun…given an array, use a function to specify which elements you’re interested in. Just like Ruby’s find and find_all methods, and Java’s FileFilter and FileNameFilter classes. It’s like I’m using a Maserati just to commute. Well, The Little Schemer is on my wishlist…it’ll be fun to try the examples in both Scheme and Ruby. Maybe even JavaScript.

Now, I went to a Java School, so I only heard about functional programming, LISP, Scheme, Ruby, and all these strange beasts once I started teaching myself off the internet. No one at any of my jobs ever mentioned them. How is it that our field can have such a rich heritage, and almost no one knows about it? Ask the person in the next cube over whether they’ve ever heard of functional programming, whether they know what it is, or can explain it to you. I guess 80% of you get blank looks. [This offer void at telcos and good universities.]

Quite a few people call that a competitive advantage. And they’re right — having scarce information puts you ahead of those without that information. But it seems short-sighted to me to gloat over that temporary advantage, when you’re missing the contributions that the people in the dark could be making.

UPDATE: It occurs to me that this might sound like I think functional programming should be used for everything — hardly the case, especially given my lack of experience with it, which I readily admit to. My point is, why don’t more of us know about it? Why isn’t it taught in more universities, or talked about at work?

New Job, No School!

I’ve been working for over 6 years for large corporations, but last week I accepted a job offer to work at a much smaller company — I’ll be employee 6 (or 7, if you count the intern). I’m really excited, my family’s excited, my current co-workers keep telling me I’ll be missed, and my new co-workers can’t wait for me to start, so it’s a pretty good time. And just because that’s how life goes, I’ll also earn my B.S. in Computer Science after 10 years of full- and part-time study.

But why mention it here? A few reasons:

  • The new job is with .Net, and my background (so far) is in J2EE. I like the thought of seeing the other side, and doing a balanced compare-and-contrast. To borrow from Neal Stephenson, “nothing teaches you about your home country like visiting a different one.” [My first impression of the differences is that Java aims to be open, but at the cost of consistency, completeness, and cohesiveness; .Net is more consistent, complete, and cohesive, but closed. That’s very general, so flame away.] Outcome: new posts.
  • My copy of the pick-axe just came in. I’ll spend the week between jobs learning some .Net, of course, but also firming up my Ruby skills. Meta-programming, dynamic typing, closures, continuations…So many neat things to learn about! Outcome: new posts.
  • I think it’s safe to call me an autodidact. Going to school was frustrating because there are so many neat things to learn, and I have to follow the curriculum. [What a whiner!] In any case, no class means I can brush off G.E.B., maybe Zen, finish Flatterland, and some other things. Outcome: probably new posts.

I’m really looking forward to the new job, and to no school. All within a few weeks of each other. It should be a good summer…