Sunday, August 29, 2010

Imitation and Repetition

I was recently reading Alice Cooper, Golf Monster: A Rock 'n' Roller's 12 Steps to Becoming a Golf Addict and had an epiphany. In one of the chapters Alice talks about the way to be great at anything. He explains one should mimic the greats by watching and then repeat what they do until it's natural. I immediately started to think about programming, of course. We all have programmers that we admire. For me, most of my admired heros are great writers. It's their advice that I adore. I soak their words in and then practice what they talk about. But, it's not the same as reading code. What Alice was talking about was studying what the greats do and repeating it until it's as natural as the way you breathe. Where can we find great code? I always felt my programming took a huge leap forward with Smalltalk. The reason I think that is now crystal clear: Smalltalk encourages you to read other people's code. All of the tools embrace reading code. If you don't know how to do something, you can search via the tools to find something similar and then repeat what they did. There is a plethora of patterns and good programming in any Smalltalk system. All of the GoF patterns came from Smalltalk originally.

That's fine and dandy, but what about Java, Python, Ruby, or other developers? It's just as easy as finding an open source framework you love and diving head first into the code. Study it, practice writing in that style, and repeat until it feels natural. Open source gives us opportunities that only Smalltalk and Lisp did in the past: a limitless supply of software to study in any language we choose. But, this begs the question: How do I know I'm studying good code? Alice touches on this in his book by saying that as you pass milestones in competence, you know what the next level looks like. Start with code that looks good to you now and keep practicing. For me, I strive for readability. How can I remove all noise until the code I write is nothing but the language of the problem I'm trying to solve. I'm always reading code to find new techniques for removing noise. I study code written in different languages and see how I can apply any new techniques in the language I am currently using. I've found a lot of gems by studying from functional programming and applying them to object-oriented languages.

This brings up another interesting observation. If it's good to read code and practice writing it, when should you use a new technique? For me, I always practice a new technique a lot before I apply it to production code. Normally, once a technique feels natural and I know it like the back of my hand. Most of the open source libraries I've written have been to explore an idea that I saw somewhere else to play around with it. There's nothing worse than not having mastery and immediately applying it because it was new at the time. Be patient. Read, code, repeat. Always be reading and practicing. It's the only way to get better.

Thursday, May 13, 2010

Partial With Frozen Arguments In Any Position

Recently, I was working on a problem where I wish I could have frozen arguments using a partial, but could not. The reason was that I needed to freeze the last argument instead of the first. Here's a simple example of what I wanted my function to behave like:
def contains_three(string):
  return '3' in string
But, I wanted to define it like so:
contains_three = functools.partial(operator.__contains__, '3')
But, partial only freezes the first arguments and you can't mix and match. I've ran into this before and I thought it would be nice to define a partial function that would allow you to freeze arguments in any position. Here's my implementation:
def custom_partial(func, *const_args, **const_kwds):
    def result(*args,**kwds):
        args_iter=iter(args)
        def convert(value):
            if value is None:
                return args_iter.next()
            else:
                return value
        to_call = map(convert, const_args)
        new_kwds = const_kwds.copy()
        new_kwds.update(kwds)
        return func(*(to_call + list(args_iter)), **new_kwds)
    return result
Is there a test? Of course, there is...
from operator import __contains__
import unittest
class Test(unittest.TestCase):
    def testContains(self):
        has_three = custom_partial(__contains__, None, '3')
        self.assertTrue(has_three('1234'))
        self.assertFalse(has_three('124'))
By looking at the test and code, the implementation I chose was to have the value of None to denote any argument I don't want to freeze. I could have created a placeholder value for it, but decided since I haven't had a need to freeze an argument with None to just leave it.

Now, I'm not excited about the implementation, but it satisfies my initial requirements. I'm going to continue to work on this to come up with something more elegant, but for now it works.

Amazon