Programming ≈ Fun

Written by Krešimir Bojčić

Why Should I Test?

Be brave

Photo credit: Wikipedia

It’s a fair question. Imagine you want to solve classical allocation problem where you need to divide sum on parts:

90/3 = [30, 30, 30]

Of course you need to accommodate for the rounding on two decimals:

100/3 = [33.33, 33.33, 33.34]

Few weeks ago I did a similar exercise as a part of coding kata. What I got was a small module under 30 LOC and with less than 5 lines methods. So it was pretty well refactored already with the TDD driving my design. That is certainly big part of writing test (organic design), but I don’t want to write about that in this post.

After couple of weeks I stumbled on the code and wasn’t too happy with the API implementation:

def self.evenly(amount, number_of_slices)
  allocator = Allocate.new
  allocator.amount = amount
  allocator.ratios = (1..number_of_slices).map { |rata| 1.to_d/number_of_slices }
  allocator.divided
end

This was better in my opinion (you know how past you is an imbecile, right?):

def self.evenly(amount, number_of_slices)
  Allocate.new.tap do |allocator|
    allocator.amount = amount
    allocator.ratios = (1..number_of_slices).map { |rata| 1.to_d/number_of_slices }
  end.divided
end

It is not important for this discussion if this is actually better. You might hate .tap and consider this a downgrade. I would say it is a matter of taste. And it is best not to discuss taste outside particular team.

So… 1 second later I’ve runned the tests, all 10 of them passed so I knew it works. And not only that, it worked like a glove!

I could almost feel brain chemistry kicking in. Ten green tests empowered my brain to stop wasting energy on cowardness and frantically running what-if scenarios. I switched to free-as-a-bird-improve-it mode. Thirty seconds later I’ve refactored it to this:

def self.evenly(amount, number_of_slices)
  Allocate.new.tap do |a|
    a.amount = amount
    a.ratios = (1..number_of_slices).map { 1.to_d/number_of_slices }
  end.divided
end

Here is full diff in all of its glory:

Diff

Now this is pretty trivial, as always with examples but imagine if it:

  • Was embedded in 50 line procedural method
  • 10 businesses depended on this
  • You had issues in the past while improving code
  • You have that method copy/pasted on x places in your code base
Would you still change it?

Testing gives you following properties that are healthy for code bases:

  • You are inclined to change code
  • You are empowered to change code
  • You have the authority to change code (yours or others)

Some organizations institutionalize cowardness. In these kind of organizations you get a place to hide. You can always say ‘That’s not my job’. While this might be a mainstream thing in company politics it is devastating for the code base. Entropy eventually wins anyway, but if you code while being terrified it wins 100 times faster and 100 times more painfully. (Pain is yours and yours customers to bare).

If you are continuously changing code without having any tests, while not running into issues, that is great. Good for you. I am not that smart so I am using all the help I can get. Anyhow:

If you are not changing code you are guaranteed not to improve it.

If you are not unit testing I encourage you to try it out. Your debugger will hate you for it, but other than that it is a pure win.

I am interested in your take on this, since this is such a essential topic I would love to hear about other angles.

« What to test? Hitchhiker Guide for Multiselect »

Comments

Copyright © 2019 - Kresimir Bojcic (LinkedIn Profile)