My StuffToDo plugin has now been improved and refactored quite a bit so it’s time to move onto a different plugin. Since I’m starting to do a lot of work in the Kanban plugin again, refactoring that plugin would be extremely useful.
The Refactoring
The first step I use when refactoring a new codebase is to use extract method to remove any copy and paste duplication. Kanban suffers from this in a few places, probably because of the rapid prototyping that was done early on.
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 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# app/models/kanban.rb class Kanban def get_backlog_issues(exclude_ids=[]) return [[]] if missing_settings('backlog') conditions = ARCondition.new conditions.add ["#{Issue.table_name}.status_id IN (?)", @settings['panes']['backlog']['status']] conditions.add ["#{Issue.table_name}.id NOT IN (?)", exclude_ids] unless exclude_ids.empty? issues = Issue.visible.all(:limit => @settings['panes']['backlog']['limit'], :order => "#{RedmineKanban::KanbanCompatibility::IssuePriority.klass.table_name}.position ASC, #{Issue.table_name}.created_on ASC", :include => :priority, :conditions => conditions.conditions) return issues.group_by {|issue| issue.priority }.sort {|a,b| a[0].position b[0].position # Sorted based on IssuePriority#position } end # TODO: similar to backlog issues def get_quick_issues return [[]] if missing_settings('quick-tasks', :skip_status => true) || missing_settings('backlog') issues = Issue.visible.all(:limit => @settings['panes']['quick-tasks']['limit'], :order => "#{RedmineKanban::KanbanCompatibility::IssuePriority.klass.table_name}.position ASC, #{Issue.table_name}.created_on ASC", :include => :priority, :conditions => {:status_id => @settings['panes']['backlog']['status'], :estimated_hours => nil}) # Returns as nested arrays return issues.group_by {|issue| issue.priority }.sort {|a,b| a[0].position b[0].position # Sorted based on IssuePriority#position } 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 27 28 29 30 31 32 33 34 35 36 37 38 |
def get_backlog_issues(exclude_ids=[]) return [[]] if missing_settings('backlog') conditions = ARCondition.new conditions.add ["#{Issue.table_name}.status_id IN (?)", @settings['panes']['backlog']['status']] conditions.add ["#{Issue.table_name}.id NOT IN (?)", exclude_ids] unless exclude_ids.empty? issues = Issue.visible.all(:limit => @settings['panes']['backlog']['limit'], :order => "#{RedmineKanban::KanbanCompatibility::IssuePriority.klass.table_name}.position ASC, #{Issue.table_name}.created_on ASC", :include => :priority, :conditions => conditions.conditions) return group_by_priority_position(issues) end # TODO: similar to backlog issues def get_quick_issues return [[]] if missing_settings('quick-tasks', :skip_status => true) || missing_settings('backlog') issues = Issue.visible.all(:limit => @settings['panes']['quick-tasks']['limit'], :order => "#{RedmineKanban::KanbanCompatibility::IssuePriority.klass.table_name}.position ASC, #{Issue.table_name}.created_on ASC", :include => :priority, :conditions => {:status_id => @settings['panes']['backlog']['status'], :estimated_hours => nil}) return group_by_priority_position(issues) end private # Sort and group a set of issues based on IssuePriority#position def group_by_priority_position(issues) return issues.group_by {|issue| issue.priority }.sort {|a,b| a[0].position b[0].position } end end |
Review
Now that the grouping method has been extracted, we can see some more duplication in the finders of these methods. And if you look at the entire class, there are even more methods that are very similar to #get_backlog_issues
and #get_quick_issues
. Refactoring those methods will be the next things I do.