Breaking down complicated code (using Ruby as an example)

Mazen Alswar
5 min readFeb 19, 2019

--

I’ve only been programming for less than a year but it’s been an amazing journey so far and I am very grateful for all the wonderful free resources there are to learn code including, freecodecamp.org, codewars.com, flatironschool.com’s bootcamp prep course and theodinproject.com which have been massive for my learning journey.

One of the websites that I really love to spend my free time (if I ever have any) trying to become a better and more well-rounded programmer is codewars.com. I love going through their challenges learning different ways of working with code. But as someone who hasn’t been programming for a long time, I found myself extremely frustrated and intimidated when I looked at how other people’s solutions fared next to mine.

Point in case, the “persistent bugger” problem, in which you are asked to:

Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.

For example:

At the outset I thought to myself “this is gonna be a piece of cake!”.

It wasn’t.

I felt like thinking of the problem in an abstract way was fairly straight forward, but when it came to translating it into code, I hit a wall. I struggled, but I kept pushing through and after some time I had a working solution!

Awesome, Right?! Nope.

So, this was my solution to the problem (this was a while ago, don’t judge me):

I was extremely proud to have a working solution but that didn’t last long. I took one look at the top couple of solutions submitted by other users and I felt like an idiot to say the least. I began to put myself down and question if I could ever become a good programmer. Thankfully, with persistence(no pun intended) I managed to leave that mindset behind.

Instead of telling myself that I’m stupid or that I lack what it takes, I spent a lot of time looking at other people’s code, especially ones that seemed extremely complex or baffling at first sight. I made sure to take time to break down problems into small solvable pieces and then bring those pieces together in an efficient whole.

Taking the “persistent bugger” problem as an example, I would break it down this way:

  1. I would check if “n” is smaller than 10; if it is, then the function will return 0.
  2. If “n” is bigger than 10 then I would have to multiply the digits, for which I need to turn “n” into an array of digits I can manipulate. To do this I would turn the number to a string using .to_s 1989 => “1989” which enables me to split it in individual digits using string methods such as .split and .chars “1989” => [“1”, “9”, “8”, “9”].
  3. Then I would .map over that array of digits(which are still strings at this point) and convert them into integers using .to_i.
  4. Now that I have an array of integers that I can keep multiplying the array elements until I end up with a single digit, as the problem requires. .reduce is a prime candidate for achieving this.

Now, if we take a peek at the top ranked solution for this problem on codewars:

The first time I saw this solution I just yelled “oh F*ck off” in frustration. Of course, this is a personal flaw that I acknowledge and try not to let get the best of me. We should never compare ourselves to others because we can never objectively nor accurately see the “full picture”. But looking at this same solution now, I find that it makes perfect sense and the use of recursion is massively important. Moreover, I am more than happy to have taken the time to understand how this solution works.

To break down how I read this solution now:

  1. Check if “n” is smaller than 10; if it is, then the function will return 0
  2. Else, recursively call the persistence function and add 1 for each time the function is run.
  3. When the recursion is done (the value of the recursion become smaller than 10 and the function has stopped calling itself) return the times 1 was added to itself.

Important note: the inner function call does not itself return anything; rather, the 1 just keeps incrementing with every call.

Another top-ranked solution that uses the same principle, but that I found to be more readable is:

While the two solutions above yield the same results, I found the second one to be more easy to comprehend because the recursion and condition to end the recursion are explicit. The former of the solutions is a bit more complicated(in my opinion) because the manner in which the recursion ends is not very clear at first sight, at least it wasn’t for me. And if you are still struggling to wrap your head around recursion properly (like me) you will definitely appreciate the added clarity in the second solution.

To conclude, as someone who hasn’t been coding for a long time, I think one of the biggest and most important lessons I’ve learned so far, is the need to breakdown and dissect complicated code. Not only will it help you learn new concepts, but looking at problems form different people’s point of view will help you immensely in looking at problems from multiple points and come up with different ways of solving those problems.

If you are interested in learning more about recursion, I would recommend you check out these resources:

Happy coding!

--

--