The Squirrel Cannon

Suppose you’re putting together an introductory Python course. You might introduce the language with a simple greeter program:
name = input("What is your name? ")
print(f"Hello, {name}!")
And then introduce function definitions, and the useful idiom of main():
def main():
name = input("What is your name? ")
print(f"Hello, {name}!")
if __name__ == '__main__':
main()
…and how to organize your code by breaking things up into smaller functions:
def get_name():
name = input("What is your name? ")
return name
def mk_greeting(name):
greeting = f"Hello, {name}!"
return greeting
def main():
name = get_name()
greeting = mk_greeting(name)
print(greeting)
if __name__ == '__main__':
main()
…and how to use classes and objects:
class Greeter:
def get_name(self):
self.name = input("What is your name? ")
def mk_greeting(self):
self.greeting = f"Hello, {self.name}!"
def main():
greeter = Greeter()
greeter.get_name()
greeter.mk_greeting()
print(greeter.greeting)
if __name__ == '__main__':
main()
…and how to anticipate edge cases and handle exceptions:
class Greeter:
def get_name(self):
self.name = input("What is your name? ")
def mk_greeting(self):
try:
self.greeting = f"Hello, {self.name}!"
except AttributeError:
self.greeting = "Hold on, I don't know who you are!"
def main():
greeter = Greeter()
greeter.get_name()
greeter.mk_greeting()
print(greeter.greeting)
if __name__ == '__main__':
main()
Because these examples are meant to introduce features of a language, the actual task being performed (greeting the user) is relatively simple. This prevents the task from being too much of a distraction, and lets you focus instead on teaching the features themselves. For the students, it’s easier to learn how the language works if they already know what the code is supposed to do.
But in making the task so simple, these examples can give the wrong idea about when to use the features. Much of the code above is completely overbuilt for something like a greeter.
This leads to the old saying: don’t hunt squirrels with a cannon.
In most cases, your choice of tools and structures should depend on the task at hand, rather than using the most powerful stuff you’ve got just because you can. New concepts are often introduced with toy examples which, in a real use-case, would be better off without using the new concept at all.
A little overbuilding is fine sometimes, especially if you want to future-proof things (or show off in a coding interview), but it’s definitely possible to go too far. To drive this point home, let’s get ridiculous and make the greeter demonstrate callbacks and I/O handling:
import sys
def read_cb(prompt="", rh=sys.stdin, wh=sys.stderr):
wh.write(prompt)
rh.readline()
def print_cb(text, wh=sys.stdout, end="\n"):
if not text.endswith(end):
text += end
wh.write(text)
class Greeter:
def __init__(read_cb):
self.read_cb = read_cb
def get_name(self):
self.name = self.read_cb("What is your name? ")
def mk_greeting(self):
try:
self.greeting = f"Hello, {self.name}!"
except AttributeError:
self.greeting = "Hold on, I don't know who you are!"
def do_greeting(read_cb, print_cb):
greeter = Greeter(read_cb)
greeter.get_name()
greeter.mk_greeting()
print_cb(greeter.greeting)
def main():
do_greeting(read_cb, print_cb)
if __name__ == '__main__':
main()
Now that’s a squirrel cannon!
In a Nutshell
A squirrel cannon is anything which is far overbuilt for the the task at hand. They’re certainly not limited to software, you can see them in all aspects of life: your friend’s gaming PC when all they play is Minesweeper, that one person who brings a giant rucksack on short hikes, the neighbor’s giant pickup truck that they never use to haul anything.
And sometimes they do make sense, like if you want to show off, or if all you have is a cannon and those squirrels won’t hunt themselves. Either way, it’s better than hunting bears with a BB gun.
| Created: | 2024-02-06 |
| Updated: | 2024-02-06 |
| Tags: | squirrels, cannons |

