Hamming coding challenge Part I
This article is the second part of Exercism's Hamming coding challenge. Initially I had explained my first solution and the lesson learnt as hinted by Exrecism. This second part focuses more on how I refactored my initial solution as seen in part I.
The refactored code goes like this:
class UnequalStrandError < ArgumentError
def initialize(error_message = 'Strands must be of equal length')
super
end
end
class Hamming
def self.compute(first_strand, second_strand)
new(first_strand, second_strand).distance
end
attr_reader :distance, :first_strand, :second_strand
private
def initialize(first_strand, second_strand)
@first_strand = first_strand
@second_strand = second_strand
validate
@distance = nucleotides.count { |n1, n2| n1 != n2 }
end
def nucleotides(first_strand, second_strand)
first_strand.chars.zip(second_strand.chars)
end
public
def validate
raise UnequalStrandError unless first_strand.length == second_strand.length
end
end
From this second iteration you can observed that it is now leaner and readable. However, what did do to make it leaner and readable?
As usual I will start with the UnequalStrandError
class. In the new code I created a function called validate
. This will take care of raising errors whenever any error is encountered in the code. Note that I now have a one line code:
raise UnequalStrandError unless first_strand.length == second_strand.length
compared to what I had earlier to help handle raising errors:
raise UnequalStrandError if first_strand.empty? && second_strand.size.positive?
raise UnequalStrandError if first_strand.size.positive? && second_strand.empty?
raise UnequalStrandError if first_strand.size > second_strand.size
raise UnequalStrandError if first_strand.size < second_strand.size
Secondly I refactored compute
as :
def self.compute(first_strand, second_strand)
new(first_strand, second_strand).distance
end
The compute method in the above is a class method as indicated with the self
prefix and also in compute body, I instatiated Hamming
class and called distance
on it.
The distance
method is defined in initialize
method:
def initialize(first_strand, second_strand)
@first_strand = first_strand
@second_strand = second_strand
validate
**@distance = nucleotides.count { |n1, n2| n1 != n2 }**
end
and it is defined as an instance variable which is then exposed using attr_reader
method.
attr_reader :distance, :first_strand, :second_strand
Note that @distance
is a variable holding the result derived from nucleotides.count { |n1, n2| n1 != n2 }
. Also the nucleotides
method defined in the body of Hamming
class handles the separation and zipping of first_strand
and second_strand
In the initial code I had used the split()
method to get an array from the string supplied but I found chars()
to be effective as well. After creating the array I zipped both first_strand
and second_strand
array together. While using the zip()
method this is what it does:
first_strand = [G,A,G,C]
second_strand = [C,A,T,C]
first_strand.zip(second_strand)
result = [[G,C],[A,A],[G,T],[C,C]]
After zipping I called the count()
method on the zipped array and this method was able to get a count of items in the sub array that are not the same.
With this refactoring for readability, I learnt about self
, and what self
means in the context of this challenge. I understood that when self
is used in a code, it refers to the class and in this case it is reffering to the class Hamming
.
I also learnt a new trick: instantiating a class in a class method and calling a defined method in the class on it.
def self.compute(first_strand, second_strand)
new(first_strand, second_strand).distance
end
When Hamming.compute
is called, the new class instantiation will also call the method involved. This is a quick way of getting results instead of having to create new objects of class Hamming
.
I also learned that, I can raise Errors in the initialize method to catch the errors thrown as quick as possible.
These are what I learned while solving the hamming coding challenge on Exercism. I will be solving more challenges on Exercism and do watch out for more articles on how I solved and refactored the challenges.
Top comments (0)