Everyone wish to write the better code, But How, Is there any pattern / behaviour? Can anyone point to your code what can be improved?
The answer is YES, There is pattern you should follow the OOPS way by it’s core. I have written SOLID principle before this, Please check this too. I am going to write more series in this topic as it’s really interesting and helpful to everyone.
In Ruby it’s damn easy but we don’t understand what mistake we are doing, so chances of improvement is less. So, Let’s take an example of below MyClass in code1 as below.
Code1:
class MyClass
attr_reader :input
def initialize(input)
@input = input
end
def double
case input
when Numeric then target . 2
when String then target.next # lazy fail ex
when Array then target.collect {|o| MyClass.new(o).double}
else
raise “don’t know how to double #{input.class} #{input.inspect}”
end
end
end
The result of the code1 is Output1 as below:
>> MyClass.new(‘aaa’).double
=> "aab"
>> MyClass.new(49).double
=> 98
>> MyClass.new([‘b’, 6]).double
=> ["c", 12]
>> MyClass.new({‘x’=>‘y’}).double
RuntimeError: don’t know how to double Hash {"x"=>"y"}
from (irb):73:in `double'
from (irb):80
from :0
The above code looks Good, Right ?
You’re probably used / gone thought with this pattern. and, Its everywhere in Ruby on Rails.
But, This style of code is Absolutely Wrong and that you should do a different thing.
Why is the problem in above code?
If I change how double works on any of these classes, MyClass must change, but that’s not the real problem. What happens if MyClass wants to double some new kind of object? I have to go into MyClass and add a new branch to the case statement. How annoying is that?
But that’s the least of it. If I’m writing code that follows this pattern, I likely have many classes that do stuff based on the classes of their collaborators. My entire application behaves this way. Every time I add a new collaborating object I have to go change code everywhere. Each subsequent change makes things worse. My application is a teetering house of cards and eventually it will come tumbling down.
Also, what if some other wishes to use MyClass with their new SuperDuperClass object? They can’t reuse MyClass without changing it since MyClass has a very limited notion of what kinds of objects can be doubled.
MyClass is both rigid and closed for extension.
Code2:
class Numeric
def double
self * 2
end
end
class String
def double
self.next
end
end
class Array
def double
collect {|e| e.double}
end
end
class Object
def double
raise "don't know how to double #{self.class} #{self.inspect}"
end
end
class MyClass
attr_reader :input
def initialize(input)
@input = input
end
def double
input.double
end
end
What basically it should be as below (Something like this) :
Using this new code, Output1 will be the same as before, but now we can also use this way as output2: