问题描述
我已经编写并优化了这样的代码
def issues_json_for_v2(skip_avatar = false)
@result_json ||= { results: [] }
return if @result_set['issues'].empty?
@result_set['total_entries'] = @result_set['meta']['total']
fr_issues = @result_set['issues']
user_hash = fr_results_hash(@result_set['users'])
project_data = fr_results_hash(@result_set['projects'])
if @suggest
add_suggest_results_fr_issues(fr_issues,project_data)
else
fr_issues.each do |issue|
p_data = project_data[issue['project_id']] if issue
if issue && issue['owner_id']
issue_json = append_fr_user_details_to_issue(safe_send(:fr_issue_json,issue,p_data),user_hash)
else
issue_json = safe_send(:fr_issue_json,p_data)
end
@result_json[:results] << issue_json
end
end
return @result_json[:results] if @size.nil?
add_fr_prj_meta_data(fr_issues)
@result_json[:results]
end
我还是得到
issue_json_for_v2的分配分支条件大小太大。
在保持可读性的同时,我可以做些什么优化。
这是我遇到此问题的另一种方法
def project_json(project,id)
human_display_id = project['key']
title = sanitize_fr_data(project['name'])
description = project['description'].blank? ? '' : project['description']
description = sanitize_fr_data(description)
prg = project['progress']
percent_completion = (prg['done'] == 0) ? 0 : (prg['done'] * 100) / (prg['todo'] + prg['in_progress'] + prg['done'])
current_time_zone = ActiveSupport::TimeZone::MAPPING[current_user.time_zone]
start_date = project['start_date'].nil? ? '--' : project['start_date'].in_time_zone(current_time_zone).strftime(date_time_format)
end_date = project['end_date'].nil? ? '--' : project['end_date'].in_time_zone(current_time_zone).strftime(date_time_format)
return { result_type: 'project',content: %{#{title} (#{human_display_id})},path: fr_project_path(project['key']) } if @suggest
{
id: id,title: title,project_display_id: human_display_id,description: truncate(description,length: 250),owner: project['owner_id'],start_date: start_date,end_date: end_date,progress: {todo: project['progress']['todo'],in_progress: project['progress']['in_progress'],done: project['progress']['done']},percent_completion: percent_completion,}
end
解决方法
ABC指标专门用于帮助提高可读性。通常,如果您达到ABC限制,则该代码的可读性可能会比您想象的要低得多,因为该方法干得太多。
我建议:
- 考虑通过该方法(分支)有多少种不同的方式
- 考虑如何测试所有这些分支,或者至少执行每个代码路径
如果您想弄清楚实际需要做什么,那么您对ABC指标所指出的内容就会有所了解。
要重构您的代码,我将:
- 将
@result_json
提取到将确保始终创建访问器方法的后面,然后在您的问题方法中调用result_json而不是@result_json
def result_json
@result_json ||= { results: [] }
end
- 分离出处理
@result_set
的逻辑-考虑创建一个包装结果集并提供适当访问器的类,例如
class ResultSet
def initialize(hsh)
@hsh = hsh
end
def total_entries
@hsh['meta']['total']
end
def issues
@hsh['issues']
end
def users
# obviously... you need the fr_results_hash method available here too
@user_hash ||= fr_results_hash(@hsh['users'])
end
def project_data
@project_data ||= fr_results_hash(@hsh['projects'])
end
end
然后,您可以在result_set = ResultSet.new(@result_set)
之类的方法中使用此方法,并直接调用result_set.project_data
之类的实例方法,而无需创建局部变量来保存每个数据。
- 假设
@result_set['issues']
是一个数组,在数组(.compact
)上调用fr_issues.compact.each do |issue|
将会从数组中删除所有nil
值,这是我想的您在if issue
块中检查fr_issues.each
时要防备。这意味着您可以删除这些条件,因为它们不会发生。
更一般而言,该方法中@variables
的使用率很高。这使得该方法在没有上下文的情况下很难理解。考虑这些对象是否真的应该是实例方法,或者应该将其范围限定在方法本身之内。
您的第二种方法有问题,这是因为三元运算的过度使用,需要将这些值分配给方法中的变量。创建一些辅助方法会有所帮助,例如:
start_date = project['start_date'].nil? ? '--' : project['start_date'].in_time_zone(current_time_zone).strftime(date_time_format)
end_date = project['end_date'].nil? ? '--' : project['end_date'].in_time_zone(current_time_zone).strftime(date_time_format)
拥有:
def format_date(value)
value.nil? ? '--' : value.in_time_zone(current_time_zone).strftime(date_time_format)
end
然后在您的方法中,只需使用format_date(project['start_date'])
和format_date(project['end_date'])
。因为调用它们没有复杂性,所以只需直接在最终哈希中调用它们,而不是将它们分配给变量即可。
同样,在返回哈希中添加方法def project_completion_percent(progress)
然后直接调用project_completion_percent(project['progress'])
将摆脱2个分配和一个分支。另一个想法...格式化description
的方法将意味着您可以摆脱方法中的2行代码,2个赋值和一个分支。
还有更多优化,但希望可以提供足够的指针