优美代码-使用冗余字段处理问题
Jan 24, 2019 00:00 · 1162 words · 3 minute read
最近在读 Andrew Hunt 与 David Thomas 的经典著作 <<程序员修炼之道>> 其中有一节在阐述程序设计中”知识”重复的危害(这里的知识是广义的, 对程序来说就是一些功能的代码), 文中提到的内容和我之前重构一个项目时遇到的问题有相似之处, 在此记录下来.
项目是一个为了促进用户消费的和粘稠度优惠券系统(商家/平台策划活动, 用户参与活动后获得优惠券并在以后的消费中使用优惠券…), 这个系统中有一个表是用来保存活动计划, 简化后的结构如下:
class ActivityPlan(BaseModel):
name, # 活动计划名称
approve, # 运营总监是否同意发布这个活动 (0: 等待审批 1: 通过, -1: 未通过)
isPublished, # 活动是否已发布 (1: 是, 0: 未发布)
endDate, # 活动结束时间
....
为了方便运营直观的了解活动计划的状态, 在后台管理的界面要展示每一个活动的状态[‘待审批’, ‘审批未通过’, ‘等待发布’, ‘活动进行中’, ‘活动已结束’….]
前端拿到活动计划后需要按照与后端的约定判断逐次判断”approve”, “isPublish”, “endDate”… 这些字段的值, 最后计算出最终的状态, 如果一但业务有新的变化, 无疑前后端都要重新制定新的规则并更改对应的代码, 这其实就是后端的”知识”在前端的重复
一次优化
class ActivityPlan(BaseModel):
name, # 活动计划名称
approve, # 运营总监是否同意发布这个活动 (0: 等待审批 1: 通过, -1: 未通过)
isPublished, # 活动是否已发布 (1: 是, 0: 未发布)
endDate, # 活动结束时间
....
state, # 状态
前端不再需要了解后端如何判断活动计划的状态, 只需要知道每一个state对应的状态是什么即可, 但对于后端来说又有了新的问题—我们需要在过去代码中所有更改”approve”, “isPublish”… 的地方添加state字段的更新, 而且如果活动已经进入发布状态, 还需要在每次返回前端前对当前时间与endDate进行比较以便确认活动是否已经结束.
再一次优化
class ActivityPlan(BaseModel):
name, # 活动计划名称
approve, # 运营总监是否同意发布这个活动 (0: 等待审批 1: 通过, -1: 未通过)
isPublished, # 活动是否已发布 (1: 是, 0: 未发布)
endDate, # 活动结束时间
....
@property
def state(self): # 状态
if self.approve == 0:
return 1001 # 待审批
elif self.approve == -2:
return 1002 # 审批未通过
....
后端只在类ActivityPlan中处理state, 而无需再其它地方处理
总结
原始代码
后端代码是简洁的, 但存在前后端”知识”(状态的判断逻辑)上的重复
第一次的改进
解决了前后端”知识”上的重复问题, 但使得后端出现状态上的重复(可以认为 state 是其它几个状态字段的冗余(由其它字段计算得来)), 同时为了保持state的正确性, 需要在代码的许多地方维护state
的二次的改进
将维护state的操作局部化到类的方法中, 而不暴露到整个后端代码中