I’m starting on some major internal refactoring of the Kanban class now. There are seven core methods that it uses and they all contain a lot of copy and paste duplication. Today I’m starting on the Finished (#get_finished_issues
) and Canceled (#get_canceled_issues
) panes since they are almost mirror images.
The Refactoring
I used extract method with a few tweaks to handle the local variables in each method that come from the settings.
Before
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# app/models/kanban.rb class Kanban def get_finished_issues return [[]] if missing_settings('finished') days = @settings['panes']['finished']['limit'] || 7 issues = Issue.visible.all(:include => :assigned_to, :order => "#{Issue.table_name}.updated_on DESC", :conditions => ["#{Issue.table_name}.status_id = ? AND #{Issue.table_name}.updated_on > ?", @settings['panes']['finished']['status'], days.to_f.days.ago]) return issues.group_by(&:assigned_to) end def get_canceled_issues return [[]] if missing_settings('canceled') days = @settings['panes']['canceled']['limit'] || 7 issues = Issue.visible.all(:include => :assigned_to, :order => "#{Issue.table_name}.updated_on DESC", :conditions => ["#{Issue.table_name}.status_id = ? AND #{Issue.table_name}.updated_on > ?", @settings['panes']['canceled']['status'], days.to_f.days.ago]) return issues.group_by(&:assigned_to) end end |
After
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# app/models/kanban.rb class Kanban def get_finished_issues get_issues_for_pane(:finished) end def get_canceled_issues get_issues_for_pane(:canceled) end private def get_issues_for_pane(pane) return [[]] unless [:finished, :canceled].include?(pane) return [[]] if missing_settings(pane.to_s) status_id = @settings['panes'][pane.to_s]['status'] days = @settings['panes'][pane.to_s]['limit'] || 7 issues = Issue.visible.all(:include => :assigned_to, :order => "#{Issue.table_name}.updated_on DESC", :conditions => ["#{Issue.table_name}.status_id = ? AND #{Issue.table_name}.updated_on > ?", status_id, days.to_f.days.ago]) return issues.group_by(&:assigned_to) end end |
Review
Now that all of the logic for #get_finished_issues
and #get_canceled_issues
has been extracted, they now read at a very high level. This also makes me wonder if I can extract the other get_pane methods into #get_issues_for_pane
. That way, everything will be isolated in one method instead of duplicated across seven different methods.