Lessons in parenting from programming principles (or vice versa)
Tell, don’t ask
I have been working on a project Airship recently adopted, providing support and adding features. One of the new features brought me face to face with an impressively nested and contorted if-statement. I needed to inject some new logic somewhere in the thick of the sprawling tendrils of its conditionals. To respect the anonymity of this particular beast, we can approximate the complexity with the incredible logistics involved in getting packed for an outing with two tiny children, which, when simplified, might look something like this:
def pack_bag(children, destination, start, stop)
bag = Bag.new
children.each do |child|
if stop - start > 1.hours || destination.distance > 5.miles
if start.month > 10 || start.month < 3 || raining?
if destination.outside?
bag.add([hat, coat])
if child.baby?
bag.add([blanket, carrier])
end
end
els
if start..stop.cover?(lunchtime)
if child.baby?
bag.add([carrier, diapers, wipes, baby_food, spoon])
else
bag.add([pb_j, apple]) unless destination.restaurant?
end
end
end
end
if (daring? && willing_to_come_back_home?) || children.count < 1
bag = nil
end
bag
end
Now, let’s add a new option. We could try “allow potty training”, or “allow optional toddler meltdown at random configuration”. It’s hard to know where to start. This code violates several basic Object-oriented Programming principles, including
Tell, Don’t Ask. The goal in programming as well as parenting would be to develop mature children objects that can perform their own functions.
def pack_bag(children, outing)
bag = Bag.new
children.each do |child|
bag.add(child.pack_my_own_stuff(outing))
end
end
But sometimes there are constraints on employing the Tell, Don’t Ask principle. Sometimes you’re not working with first-class, high level objects. Sometimes you’re given wee-little, wide-eyed hashes or chubby-cheeked, utterly dependent list of arguments to work with. In this case you need to take patient steps in the direction of Tell, Don’t Ask, but aware that you still need to provide thoughtful guidance. Here are a few ideas to help you through the baby stages:
- Clarify your questions. Phrase the question so your toddler understands you. This helps you know what they are saying yes to, because children answer yes or no whether they really understand the question or not. Transform esoteric conditionals into English:
def coat_weather?(start)
start.winter? || start.raining?
end
def winter?
month > 10 || month < 3
end
2. Limit your questions. A good rule of thumb is to give your toddler 2 choices, both of which have outcomes you approve of. Factor by major distinctions:
pack_baby_bag if child.baby?
pack_toddler_bag if child.toddler?
3. Be explicit and concise about the behavior you are expecting. Provide sufficient and necessary instructions.
def pack_baby_bag
pack_food
pack_diapers
pack_clothes
end
As with all parenting and programming advice, there’s no general solution that always works. Pay attention to what is developmentally appropriate for your situation. You don’t want to coddle badly written code and keep it from refactoring into responsible objects. On the other hand, don’t push your code to independence before it is ready.