In Progress
Unit 1, Lesson 21
In Progress

Hammers And Diapers

Video transcript & code

You've heard the old saying: when you have a hammer, everything looks like a nail. Sometimes, a programming language can be that hammer.

For instance. I have this book I'm pre-selling. Whenever someone completes a purchase at the third-party storefront, an app of mine receives a callback with a bunch of sale information, known as "IPN data".

post "/ipn" do
  # ...
end

Unfortunately, sometimes things go wrong and the IPN callback doesn't complete successfully. For this reason, I've set up a Rake task that allows me to simulate an IPN callback with a given email address.

 $ bundle exec rake send_ipn[kirk@example.org]
I, [2015-08-11T12:10:33.250447 #31148]  INFO -- : Send IPN for kirk@example.org
I, [2015-08-11T12:10:33.254579 #31148]  INFO -- : post http://localhost:5678/ipn
I, [2015-08-11T12:10:33.343747 #31148]  INFO -- Status: 202

This is great for when something breaks, or when someone loses their original invitation. I can just run their email address through again as if they had just bought the book.

But the other day I found myself with a long list of about 100 missing email addresses that I needed to import into the system.

 $ cat missing_emails.txt
deshawn.leuschke@example.org
emmanuel_windler@example.com
beaulah_bergnaum@example.net
angelita@example.com
...

Once I saw this bulk data, I immediately set to work building a new Rake task for importing lists of emails. This entailed writing some new library code to support it. In the process, I also started refactoring the existing IPN handling code so that I could re-use parts of it in the import process.

Halfway through this process, I was interrupted. My youngest child was pair-programming with me in my lap at the time, and it became fragrantly clear that it was time for a diaper change.

Now, there is nothing quite like a stinky diaper to clear the mind and reset your problem-solving process. When I finished, I sat down in front of my computer again and deleted all the code I had just written.

$ git reset --hard HEAD

Instead of writing more code, I went to the command line and typed out the following command:

$ cat missing_emails.txt | xargs -I {} echo bundle exec rake send_ipn[{}]
bundle exec rake send_ipn[deshawn.leuschke@example.org]
bundle exec rake send_ipn[emmanuel_windler@example.com]
bundle exec rake send_ipn[beaulah_bergnaum@example.net]
bundle exec rake send_ipn[angelita@example.com]
bundle exec rake send_ipn[sally_okon@example.com]
...

This command uses the UNIX xargs utility to repeat a sub-command once for each email address. Once I was satisfied that this use of xargs would generate the appropriate series of individual commands, I removed the echo and executed it again. Then I went and worked on something else while it chugged away.

 $ cat missing_emails.txt | xargs -I {} bundle exec rake send_ipn[{}]
I, [2015-08-11T12:26:31.823139 #31501]  INFO -- : Send IPN for deshawn.leuschke@example.org
I, [2015-08-11T12:26:31.827192 #31501]  INFO -- : post http://localhost:5678/ipn
I, [2015-08-11T12:26:31.894517 #31501]  INFO -- Status: 202
I, [2015-08-11T12:26:32.293846 #31507]  INFO -- : Send IPN for emmanuel_windler@example.com
I, [2015-08-11T12:26:32.298201 #31507]  INFO -- : post http://localhost:5678/ipn
I, [2015-08-11T12:26:32.376171 #31507]  INFO -- Status: 202
I, [2015-08-11T12:26:32.785454 #31512]  INFO -- : Send IPN for beaulah_bergnaum@example.net
I, [2015-08-11T12:26:32.789490 #31512]  INFO -- : post http://localhost:5678/ipn
I, [2015-08-11T12:26:32.872700 #31512]  INFO -- Status: 202
I, [2015-08-11T12:26:33.317185 #31518]  INFO -- : Send IPN for angelita@example.com
I, [2015-08-11T12:26:33.321215 #31518]  INFO -- : post http://localhost:5678/ipn
I, [2015-08-11T12:26:33.403247 #31518]  INFO -- Status: 202
I, [2015-08-11T12:26:33.858575 #31523]  INFO -- : Send IPN for sally_okon@example.com
I, [2015-08-11T12:26:33.862616 #31523]  INFO -- : post http://localhost:5678/ipn
I, [2015-08-11T12:26:33.934851 #31523]  INFO -- Status: 202
...

What I had realized while I was away from the keyboard, changing that diaper, was that I had been needlessly over-thinking the problem. Sure, a hand-coded bulk import feature would have been much more efficient. And maybe, if I had had 1000 or 10,000 emails to import, that would have mattered. But I didn't. And with the amount of data that I had to work with, coding and then testing a custom solution was overkill. I had the tools I needed right in front of me the whole time.

By the way, if you're a command-line purest you might be shaking your head at my extraneous use of cat, when I could have used a shell redirect. What can I say; I like my pipelines to flow from left to right.

$ xargs -I {} bundle exec rake send_ipn[{}] < missing_emails.txt

And that's all for today. Watch out for those hammers, and happy hacking!

Responses