How to Write Awesome code – Ruby on Rails – V1

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.

focus on one thing
Focus on one thing in a Class

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:

Output2:

>> 'aaa'.double
=> "aab"
>> 49.double
=> 98
>> ['b', 6].double
=> ["c", 12]

In this above code2,

The Objects are what they are and because of that, they actually behave the way they do.

Above statement is very simple but incredibly important.

They tell each other what, not how.

What is the event/notification/request and it is the responsibility of the sender.(sender should know).

How is the behaviour/implementation and it should be completely hidden in the receiver (sender not required to know).

Therefore:

  • MyClass should not know how Numeric implements double.
  • MyClass should just ask target to double itself.
  • All possible targets must implement double.
  • Object should implement double to help you get your Ducks in a row.

Thanks for reading. For more information I highly recommend to read Sandi Metz books.

Courtesy 99 Bottles of OOP by Sandi Metz.

Sandi metz

Happy Learning & Coding!

Note: This concept can be used with any programming language.

SOLID Principle in Ruby on Rails

SOLID Stands for:

  • Single responsibility principle
  • Open/closed principle
  • Liskov substitution principle
  • Interface segregation principle
  • Dependency inversion principle

The acronym stands for principles to help software engineers to create / write maintainable source code for long-term that use an OOPS language.

Single responsibility principle: Focus on One thing in a Class Seprately.

Open/closed principle: Class should be open for extension and closed for modification.

 Liskov substitution principle: The derived class must be capable of being substituted by its base class.

Interface Segregation principle:

Interface Segregation Principle (1996)

Dependency Inversion principle (DIP): Now a days used with Docker, Docker composer.

The Dependency Inversion Principle

Simple Bubble Sort Algorithm in Ruby – Explained

Bubble

Can you write a Bubble sort in ruby?

The interviewer usually asks sorting algorithm and mostly the bubble sorting methods in the their interview. As that is one of the most commonly asked questions in sorting algorithm. So, I thought to share that in my blog here.

Bubble Sort

The bubble sort makes the larger elements (“big bubble”) towards the end and the smaller elements (“small bubble”) towards the starting point until all the elements reach in their correct location. i.e in proper sorted order from Small to Big sort.

# A method to define the bubble sort
def bubble_sort(array)
  # condition: When array has more than one element
  if array.count > 1
    swap = true
    # Loop: Run until swap is true
    while swap
      swap = false
      # Loop: Run loop with array counts and swap if 
      (array.length-1).times do |z|
        if array[z] > array[z+1]
          # swap if current number element is greater than next number element.
          array[z], array[z+1] =  array[z+1], array[z]
          # as we we have current number element is greater than next number element
          # so we updated more swap needed.
          swap = true
        end
      end
    end
    # While loop will stop once  array[z] > array[z+1] will be false 
    # then swap will become false line number 8.
  end
  array
end


print "Befor sort - #{[7,9,3,5,4,2,1]}"
print "\n"
print "After sort - #{bubble_sort([7,9,3,5,4,2,1])}"
print "\n"


When you will run the above code( Public Gist here). tath will Result as below:

bubble sorted result

Thank you!

To upgrade ruby 2.x to ruby 2.7 and rails 4.x to rails 6.0

Ruby on Rails update

It’s very rare to directly update from ruby 1.8.7 or ruby 2.0 to ruby 2.7 and rails 4 to rails 6.0. As I have recently done many upgrade projects from legacy ruby code to new ruby code. So, I thought to help other developers too.

How?

To do so, I have got the advantage of working from Ruby 2.x to the current version of ruby to I know each and everything from legacy plugin development age to gems and then gems to new replaced gems(if depreciated).

What?

For a small project, I would rather suggest installing a fresh project in the latest ruby and latest rails there. Now, I will replace the app folder of the old code into a new project.

also, I will keep adding configurations carefully as it’s mainly updated.

GEMS:

Regarding other gems, go to their GitHub documentation and check if the community is active (check using the last commit), if yes then you can install with their latest version without setting the gem version. i.e. gem install devise and add gem 'devise' in your Gemfile.

Migration:

and most important is the GEMS, from the old file, remove all ruby and rails related gems to transfer as new rails is already installed.

In migrations, you will have to add `[6.0]` in migration.

Webpacker update:

Ideally, we should use webpacker with rails 6, but As most clients don’t give time to re-write the javascript code with webpacker. So, It’s better to use normal javascript as in-app/assets folder.

And

For better projects management, we should follow the process:

  1. Prepare the List of Decreciated gems. Identify all possible new gems which can be used also if required or not.
  2. Prepare the documentation of changes required.
  3. Prepare the timelines accordingly.
  4. Work on ROR update as per your plan.
  5. Always use another branch for any kind of upgrades. and never use the master branch for an upgrade.
  6. Try to write the test cases as well so that you will be sure about the functionality is working properly.
ruby on rails

Feel free to let me know if you face any issue or wish me to work on your ruby on rails update. I will be happy to assist.

Thanks,

Manish S