序言:时间是我们最宝贵的财富,珍惜手上的每个时分
目录
1.非必要,不修改、不优化
2.需修改、需优化、搞彻底
随着工作年限的增长,接触到的二手代码也越来越多,无论是同事离职留下的垃圾代码,还是接手烂摊子项目代码,都绕不开这个主题:代码优化。
当然并非所有的代码都需要去优化,毕竟在能用的情况下,优化代码带来的价值远可能低于付出的成本。
我遵循的准则
1)非必要,不修改、不优化。
2)需修改、需优化、搞彻底。
接手代码的第一步:结合项目整体需求,分析代码是否需要优化。
1.非必要,不修改、不优化
例如:前阵子接手的报表功能模块主要功能代码如下,
def compute_sale_cost(self, invoice_lines):sale_cost = 0for sale_cost_id in self.env.company.in_come_cost_report_config_id.sale_cost_ids:invoice_line_ids = invoice_lines.filtered(lambda x: x.account_id.id == sale_cost_id.account_id.id)# print('111111',invoice_lines)if sale_cost_id.type == 'debit':sale_cost += sum(invoice_line_ids.mapped('debit'))if sale_cost_id.type == 'credit':sale_cost += sum(invoice_line_ids.mapped('credit'))return sale_costdef compute_material_cost(self, invoice_lines):material_cost = 0for material_cost_id in self.env.company.in_come_cost_report_config_id.material_cost_ids:invoice_line_ids = invoice_lines.filtered(lambda x: x.account_id.id == material_cost_id.account_id.id)if material_cost_id.type == 'debit':material_cost += sum(invoice_line_ids.mapped('debit'))if material_cost_id.type == 'credit':material_cost += sum(invoice_line_ids.mapped('credit'))return material_costdef compute_labor_cost(self, invoice_lines):labor_cost = 0for labor_cost_id in self.env.company.in_come_cost_report_config_id.labor_cost_ids:invoice_line_ids = invoice_lines.filtered(lambda x: x.account_id.id == labor_cost_id.account_id.id)if labor_cost_id.type == 'debit':labor_cost += sum(invoice_line_ids.mapped('debit'))if labor_cost_id.type == 'credit':labor_cost += sum(invoice_line_ids.mapped('credit'))return labor_costdef compute_mrp_cost(self, invoice_lines):mrp_cost = 0for mrp_cost_id in self.env.company.in_come_cost_report_config_id.mrp_cost_ids:invoice_line_ids = invoice_lines.filtered(lambda x: x.account_id.id == mrp_cost_id.account_id.id)if mrp_cost_id.type == 'debit':mrp_cost += sum(invoice_line_ids.mapped('debit'))if mrp_cost_id.type == 'credit':mrp_cost += sum(invoice_line_ids.mapped('credit'))return mrp_cost@api.modeldef get_now_data(self, *kw):try:wizard_id = kw[0]['report_id']allowed_company_ids = kw[0]['allowed_company_ids']wizard_id = self.env['ro.income.cost.report.wizard'].sudo().search([('id', '=', wizard_id)])period_ids = wizard_id.period_ids# 会计日期数据存放列表period_data = []# 清洗会计日期数据for period_id in period_ids:period_dict = {'period_id': period_id,'date_start': period_id.date_start,'date_end': period_id.date_end}period_data.append(period_dict)partner_ids = wizard_id.partner_ids# 客户数据存放列表partner_data = []if not partner_ids:partner_ids = self.env['res.partner'].sudo().search([])# 清洗客户数据for partner_id in partner_ids:partner_dict = {'partner_id': partner_id,'id': partner_id.id}partner_data.append(partner_dict)# 所有客户的订单明细行sale_order_line_ids = self.env['sale.order.line'].sudo().search([('order_partner_id', 'in', partner_ids.ids), ('company_id', 'in', allowed_company_ids)])# 销售订单明细行存放列表sale_order_line_data = []for sale_order_line_id in sale_order_line_ids:out_going_number = sale_order_line_id.order_id.picking_ids.mapped('name')out_going_number = ','.join(out_going_number)# print(sale_order_line_id.invoice_lines)if wizard_id.invoice_range:invoice_lines = sale_order_line_id.invoice_lines.filtered(lambda x: x.move_id.state == 'posted' or x.move_id.state == 'draft' or x.move_id.state == 'approval' or x.move_id.state == 'approved')else:invoice_lines = sale_order_line_id.invoice_lines.filtered(lambda x:x.move_id.state == 'posted')sale_order_line_dict = {'sale_order_line_id': sale_order_line_id,'sale_order_name': sale_order_line_id.order_id.name,'out_going_number': out_going_number,'partner_name': sale_order_line_id.order_partner_id.name,'default_code': sale_order_line_id.product_id.default_code if sale_order_line_id.product_id.default_code else '/','product_name': sale_order_line_id.product_id.name,'product_uom_qty': sale_order_line_id.product_uom_qty,'amount': sale_order_line_id.price_subtotal,'amount_tax': sale_order_line_id.price_total,'date_order': sale_order_line_id.create_date,'invoice_lines': invoice_lines}sale_order_line_data.append(sale_order_line_dict)# 遍历期间data = []for period_id in period_data:# 拿到期间内的明细行sale_order_line_ids = [d for d in sale_order_line_data ifperiod_id['date_start'] < d['date_order'].date() < period_id['date_end']]for sale_order_line_id in sale_order_line_ids:sale_cost = wizard_id.compute_sale_cost(sale_order_line_id['invoice_lines'])material_cost = wizard_id.compute_material_cost(sale_order_line_id['invoice_lines'])labor_cost = wizard_id.compute_labor_cost(sale_order_line_id['invoice_lines'])mrp_cost = wizard_id.compute_mrp_cost(sale_order_line_id['invoice_lines'])row = [sale_order_line_id['sale_order_name'], sale_order_line_id['out_going_number'],sale_order_line_id['partner_name'], sale_order_line_id['default_code'],sale_order_line_id['product_name'], sale_order_line_id['product_uom_qty'],sale_order_line_id['amount'], sale_order_line_id['amount_tax'],sale_cost, material_cost, labor_cost, mrp_cost]if wizard_id.filter_zero:result = all(x == 0 for x in row[5:]) or all(x == '/' for x in row[5:])if result is True:continuedata.append(row)period_name = ','.join(period_ids.mapped('name'))except Exception as e:print(e)data = []period_name = ''# print(period_name)result = {# 'header': headers,'body': data,'period_name': period_name,'company_name': self.env.company.name}return result
细细品味(劝你别品)如上代码,并依据需求测试,可以分析得到:
1、功能可用,主逻辑清晰
2、核心函数get_now_data代码冗余(构造多个无用数组)
3、计算方法compute_xx_cost 方法冗余(实际为同一个计算方法,不同参数)
可优化的点
1、合并优化 compute_xx_cost 方法为一个方法
2、优化冗余构造数组
综上分析, 虽然代码冗余,但是功能完整且基本不影响用户操作,且后续不需要更新升级。即:非必要。
那么我会会遵循 1)非必要,不修改、不优化的规则,
2.需修改、需优化、搞彻底。
例如:还是前阵子接手的另一个报表功能模块,主要功能代码如下
200多行实在展开困难,我节选给各位感受感受:
其一
# 处理日期for period_id in wizard_id.fiscalyear_id.period_ids:if period_id.date_start.month == 1:fiscalyear_data['one_date_start'] = period_id.date_startfiscalyear_data['one_date_end'] = period_id.date_endelif period_id.date_start.month == 2:fiscalyear_data['two_date_start'] = period_id.date_startfiscalyear_data['two_date_end'] = period_id.date_endelif period_id.date_start.month == 3:fiscalyear_data['three_date_start'] = period_id.date_startfiscalyear_data['three_date_end'] = period_id.date_endelif period_id.date_start.month == 4:fiscalyear_data['four_date_start'] = period_id.date_startfiscalyear_data['four_date_end'] = period_id.date_endelif period_id.date_start.month == 5:fiscalyear_data['five_date_start'] = period_id.date_startfiscalyear_data['five_date_end'] = period_id.date_endelif period_id.date_start.month == 6:fiscalyear_data['six_date_start'] = period_id.date_startfiscalyear_data['six_date_end'] = period_id.date_endelif period_id.date_start.month == 7:fiscalyear_data['seven_date_start'] = period_id.date_startfiscalyear_data['seven_date_end'] = period_id.date_endelif period_id.date_start.month == 8:fiscalyear_data['eight_date_start'] = period_id.date_startfiscalyear_data['eight_date_end'] = period_id.date_endelif period_id.date_start.month == 9:fiscalyear_data['nine_date_start'] = period_id.date_startfiscalyear_data['nine_date_end'] = period_id.date_endelif period_id.date_start.month == 10:fiscalyear_data['ten_date_start'] = period_id.date_startfiscalyear_data['ten_date_end'] = period_id.date_endelif period_id.date_start.month == 11:fiscalyear_data['eleven_date_start'] = period_id.date_startfiscalyear_data['eleven_date_end'] = period_id.date_endelif period_id.date_start.month == 12:fiscalyear_data['twelve_date_start'] = period_id.date_startfiscalyear_data['twelve_date_end'] = period_id.date_end
其二:
all_year_amount = 0later_year_amount = 0one_all = 0two_all = 0three_all = 0four_all = 0five_all = 0six_all = 0seven_all = 0eight_all = 0nine_all = 0ten_all = 0eleven_all = 0twelve_all = 0for child in data:if child[0] == '合计':breakone_all += child[2]two_all += child[3]three_all += child[4]four_all += child[5]five_all += child[6]six_all += child[7]seven_all += child[8]eight_all += child[9]nine_all += child[10]ten_all += child[11]eleven_all += child[12]twelve_all += child[13]all_year_amount += child[14]later_year_amount += child[16]print(all_year_amount)if all_year_amount != 0:one_rate = one_all / all_year_amount * 100two_rate = two_all / all_year_amount * 100three_rate = three_all / all_year_amount * 100four_rate = four_all / all_year_amount * 100five_rate = five_all / all_year_amount * 100six_rate = six_all / all_year_amount * 100seven_rate = seven_all / all_year_amount * 100eight_rate = eight_all / all_year_amount * 100nine_rate = nine_all / all_year_amount * 100ten_rate = ten_all / all_year_amount * 100eleven_rate = eleven_all / all_year_amount * 100twelve_rate = twelve_all / all_year_amount * 100else:one_rate = 0two_rate = 0three_rate = 0four_rate = 0five_rate = 0six_rate = 0seven_rate = 0eight_rate = 0nine_rate = 0ten_rate = 0eleven_rate = 0twelve_rate = 0
其三:
print(cost_id)# 筛选一月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['one_date_start'], fiscalyear_data['one_date_end'])# 一月份该科目销售费用one_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选二月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['two_date_start'], fiscalyear_data['two_date_end'])# 二月份该科目销售费用two_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选三月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['three_date_start'], fiscalyear_data['three_date_end'])# 三月份该科目销售费用three_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选四月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['four_date_start'], fiscalyear_data['four_date_end'])# 四月份该科目销售费用four_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选五月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['five_date_start'], fiscalyear_data['five_date_end'])# 五月份该科目销售费用five_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选六月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['six_date_start'], fiscalyear_data['six_date_end'])# 六月份该科目销售费用six_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选七月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['seven_date_start'], fiscalyear_data['seven_date_end'])# 七月份该科目销售费用seven_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选八月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['eight_date_start'], fiscalyear_data['eight_date_end'])# 八月份该科目销售费用eight_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选九月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['nine_date_start'], fiscalyear_data['nine_date_end'])# 九月份该科目销售费用nine_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选十月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['ten_date_start'], fiscalyear_data['ten_date_end'])# 十月份该科目销售费用ten_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选十一月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['eleven_date_start'], fiscalyear_data['eleven_date_end'])# 十一月份该科目销售费用eleven_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)# 筛选十二月内该科目的凭证account_move_line_filtered_ids = self.compute_line_ids(cost_id, account_move_line_ids, fiscalyear_data['twelve_date_start'], fiscalyear_data['twelve_date_end'])# 十二月份该科目销售费用twelve_cost_amount = self.compute_amount(cost_type, account_move_line_filtered_ids)return one_cost_amount, two_cost_amount, three_cost_amount, four_cost_amount, five_cost_amount, six_cost_amount, seven_cost_amount, eight_cost_amount, nine_cost_amount, ten_cost_amount, eleven_cost_amount, twelve_cost_amount
OKOK,难以想象,这里总共300多行代码,是以什么样的毅力写下来的?脑子里蹦出的是拉三(拉赫玛尼诺夫第三钢琴协奏曲)的旋律,以及拉三的趣闻。
好笑归好笑,但是这代码是有问题的,测时候发现数据不对,我们进一步分析:
1、功能不可用,主逻辑不清晰
2、核心函数get_now_data代码冗余
1)冗余循环
2)冗余数组构造
3)冗余变量设置
当我们看到 功能不可用,且主逻辑不清晰的代码时,请一定放弃抵抗:不要在原功能上修改,请直接重新捋逻辑,彻底重构,否则你将陷入 前人留给你的逻辑漩涡中无法自拔!
这是血泪的教训,你觉得似乎只是一个小问题,但是永远改不好!
最后我遵循 2)需修改、需优化、搞彻底的规则,将其完全重构:既减少了重新阅读代码,debugger的时间,也增加了代码的可读性,为后续更新升级提供良好基础,降低屎山代码形成的可能性。
完全重构后的代码:
其一、二、三的功能重构
for account_id in account_ids:amount = 0val = ['[%s]%s' % (account_id.code, account_id.name)]for period_id in wizard_id.fiscalyear_id.period_ids:date_start = period_id.date_startdate_end = period_id.date_endaccount_move_ids = account_move_line_ids.filtered(lambda x: x.account_id == account_id and x.date >= date_start and x.date <= date_end)account_amount = sum(account_move_ids.mapped('credit'))val.append(account_amount)amount += account_amountval.append(amount)if all_amount != 0:percent = amount / all_amountelse:percent = 0val.append(percent * 100)last_amount = sum(last_year_account_move_line_ids.filtered(lambda x: x.account_id == account_id).mapped('credit'))val.append(last_amount)data.append(val)