I was thinking of finishing off an InvokeDynamic post that’s been languishing as a draft for a couple of weeks now, but having worked on more than a few dynamically-typed codebases in the past couple of months I decided to change tack and
rant make observations about design patterns instead.
To be specific, I’ve seen a lot of code written in Python which is perfectly well structured but eschews many of the constructs dynamic languages give you to make it more succinct and less repetitive (without compromising readability / maintainability). It’s surprising to see even experienced developers missing opportunities to aptly DRY shit up, so I’m going to take a couple of leaves out of Peter Norvig’s presentation reconciling typical GoF patterns with the features of a language like Python. Norvig contends that of the 23 original patterns presented in the Gang of Four book, 16 either become redundant or qualitatively simpler when implemented in a dynamic language. There are a couple of recurring points where refactoring is so obvious it’s almost silly not to do, so I’ll focus on them. First up:
Template Method Pattern
I started with templates because you probably use them all the time without realising it. The wikipedia example cites a Java app where each concrete type has a few methods to implement, but in practice it’s quite common to see something like this:
def setup_something(): # do some kind of setup return 1 def finish_doing_something(arg): # do something else print(str(arg)) def some_method_a(): a = setup_something() # logic unique to this function, e.g.: a = 2 finish_doing_something(a) def some_method_b(): b = setup_something() # logic unique to this function, e.g.: b = 3 finish_doing_something(b)
The only invariant in those two functions is a 1-liner. Imagine it isn’t, and the logic surrounding this work is also more involved than returning a number; this happens all the time in web applications that require some initial and final filtering / decorating of values, or to commit something to a database, e.t.c. I’d like to say I’ve seen this DRYed up in statically-typed languages like Java with a nice wikipedia-like solution, but too often people just copy and paste the same ritual and change what they need (an IDE can do this kind of thinking for you, right?). Without the nominative typing thrust in your face, it’s equally tempting to do the same- but first-class functions give you an easy way out:
def setup_something(): # do some kind of setup return 1 def finish_doing_something(arg): # do something else print(str(arg)) def do_work(work): val = setup_something() return finish_doing_something(work(val)) def some_method_a(): return do_work(lambda val: 2) def some_method_b(): return do_work(lambda val: 3)
OK, the payback of a few single-line methods is negligible but I bet your average Django app has a lot of easy pickings if you wanted to apply this.
Frankly, if you’re going to drop all the interesting bits of a language that SICP gave us, why not use C++? One answer may be that to really develop the part of your brain that decomposes code more effectively you have to use a language that’s so far removed from commonly used imperative languages that you have to. But that’s for another rant. I’ll just leave you with this motivational video next time you’re holding off on a refactoring: