Some popular Refactoring techniques
- Tram Ho
In the process of code, I find that with functions that are written too many lines, especially in the function, many functions often cause many problems such as:
- Difficult to control, difficult to reuse and easily cause bugs because handling too much logic in the function
- It takes a long time for review to affect the progress of the project
In addition, there are some other issues such as comments, criticism of stupid code. And to partly limit these problems, I would like to introduce to you three common techniques commonly used to re-structure the function without changing its behavior. Let’s follow and apply you guys. Let’s go!
Technique 1: Extract Method
Understanding this technique is to separate the code in a bloated function into smaller functions that only perform one of your functions.
Let’s look at an example:
1 2 3 4 5 6 7 | @sold_items =% w (onions of garlic potatoes) def print_report puts "*** Sales Report for # {Time.new.strftime ('% d /% m /% Y')} ***" @ sold_items.each {| item | puts item} puts "*** End of Sales Report ***" end |
We can separate the processing of the current date into a separate function as follows:
1 2 3 4 5 6 7 8 9 | def print_report puts "*** Sales Report for # {current_date} ***" @ sold_items.each {| i | puts i} puts "*** End of Sales Report ***" end def current_date Time.new.strftime ("% d /% m /% Y") end |
Now it seems to be easier to read, but we can add some more functions to try it out:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | def print_report print_header print_items print_footer end def print_header puts "*** Sales Report for # {current_date} ***" end def current_date Time.new.strftime ("% d /% m /% Y") end def print_items @ sold_items.each {| i | puts i} end def print_footer puts "*** End of Sales Report ***" end |
It seems to be longer, but the functions it explicitly looks easier to read, don’t you.
Technique 2: Refactoring Conditionals
You can also refactor complex conditions into methods to make them easier to read.
Let’s look at an example:
Are you familiar with how to set this condition?
1 2 3 4 | def check_temperature temperature> 30 && (Time.now.hour> = 9 && Time.now.how <= 17) air_conditioner.enable! end |
It’s easy to see the second part of an if
condition is not easy to read, so we should split it into a method:
1 2 3 4 5 6 7 8 9 | def check_temperature if temperature> 30 && working_hours air_conditioner.enable! end end def working_hours Time.now.hour> = 9 && Time.now.how <= 17 end |
It’s easier to read, right? This makes things much easier for those who read this code in the future.
Technique 3: Replace Method with Method Object
Sometimes you have a big way out of control. In this case it may be difficult to refactoring because large methods tend to have many local variables. One solution is to use Method Object
refactoring technique.
Let’s look at an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | require 'socket' MailSender class def initialize @sent_messages = [] end def send_message (msg, recipient = "sample@email.com") raise ArgumentError, "message too small" if msg.size <5 formatted_msg = "[New Message] # {msg}" TCPSocket.open (recipient, 80) by | socket | socket.write (formatted_msg) end @send_messages << [msg, recipient] puts "Message sent." end end sender = MailSender.new sender.send_message ("testing") |
To perform refactoring, we can create a new class and convert local variables into instance variables. This helps us refactor this code without worrying about data transmission.
This is the MailSender
class after being restructured:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | MailSender class def initialize @sent_messages = [] end def deliver_message (message) send (message) @send_messages << message puts "Message sent." end def send (msg) TCPSocket.open (msg.recipient, 80) {| socket | socket.write (msg.formatted_msg)} end end |
And this is the new class that we define:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Message class attr_reader: msg,: recipient def initialize raise ArgumentError, "message too small" if msg.size <5 @msg = msg @recipient = recipient end def formatted_msg "[New Message] # {msg}" end end sender = MailSender.new msg = Message.new ("testing") sender.deliver_message (msg) |
Is it really clear to see you?
Conclusion
The above are just three of many techniques to re-structure the code. Using these techniques will help you follow the Single Responibility Principle principle and keep your classes and methods in check.
If you like this post, share it with your friends so they can enjoy it too!
Article source: Introduction to Refactoring