Sunday, April 10, 2016

Learnings along the way of completing the Roman Numerals Kata via Exercism

  • Roman Numerals Kata
    • Things that I applied or learnt along the journey that led to the final solution -
    • Approach the problem in small steps. I was solving this kata for the first time, I didn't know of any pattern whatsoever initially, hence took this problem, one step at a time and it eventually helped me get to solution. Often times one worries about the end solution or just the destination, without traveling the journey bit by bit.
      • I know you may think this approach(solving for one test at a time as done in this commit and this one) wouldn't give you the desired solution that'll satisfy all cases, but trust me it will help you eventually get there. That's why this approach is worth it.
    • Used the older hash syntax in ruby so that I could leverage keys as strings. With this I could do away with the to_s that I was using here.
    • Learnt that I don’t have to use a more higher order class like the Numeric class. Instead, I could use Fixnum. I also learnt about the hierarchy of these classes. Numeric is the parent of Integer which in turn is the parent of Fixnum.
    • Learnt that reverse_each is much faster than using reverse.each and made the relevant refactoring here
    • Refactoring related learnings * When I was looking at other people's solution like that of rwz's, I realized I can define my ROMAN_NUMERALS related hash in the reverse order like what was done here and thereby I wouldn't even need to use the reverse_each method, saving me an additional computation. * I learnt that I could further simplify my solution after referring to rwz's solution. The if...else related branches that I had introduced to handle the subtractive notation related to roman numerals can be dealt without using that amount of branching. I made the relevant changes wrt this learning in this commit. * Learnt how we could use each_with_object to do away with a temp variable from henrik's solution. Appropriate change was made in this commit. Below is how the code looks before and after using each_with_object

Before

  def to_roman
    num = ''
    number_to_convert = self

    ROMAN_NUMERALS.each do |roman_numeral, numeric_equivalent|
      next if numeric_equivalent > number_to_convert

      quotient, remainder = number_to_convert.divmod(numeric_equivalent)
      number_to_convert = remainder
      num << roman_numeral * quotient
    end

    num
  end

After

  def to_roman
    number_to_convert = self

    ROMAN_NUMERALS.each_with_object("") do |(roman_numeral, numeric_equivalent), roman_equivalent|
      next if numeric_equivalent > number_to_convert

      quotient, remainder = number_to_convert.divmod(numeric_equivalent)
      number_to_convert = remainder
      roman_equivalent << roman_numeral * quotient
    end
  end
  

I don't want to write code for special cases until I understand the general case first.

 For me, this was something I wasn't doing very consciously all this while but I felt, it's definitely something              worth reflecting upon and further experimenting with.
  • Wrapping up, I would like to thank Jim for the above thought and for his work that has helped so many people. Also, my learnings here wouldn't have been possible without those who've contributed to exercism and to those whose solution I had an opportunity to refer to. I'm thankful to them as well.

No comments:

Post a Comment