从600行"状态地狱"到可维护策略模式:一次列表操作限制重构实践
描述问题
背景
随着项目的发展,列表操作限制的代码变得越来越臃肿。这段代码根据数据的状态值来判断操作,而状态值超过29种,原有实现方案采用多层嵌套的if-else逻辑判断操作可见性,导致代码行数逼近600行。代码冗余且逻辑复杂,不仅难以维护,还严重影响了页面的交互体验。列表在加载时,操作列的渲染总是出现卡顿,10条数据时操作列会延迟0.5秒显示,切换每页显示条数时,甚至会延迟1秒以上。这不仅让开发人员在维护时感到棘手,也让用户在使用时体验感极差。
现象
- 代码膨胀:操作限制判断逻辑分散在5个不同文件中,存在状态值硬编码87处
- 性能瓶颈:10条数据时操作列渲染耗时526ms,50条数据时出现1.3秒的明显卡顿
- 维护困境:最近三个月新增的5个状态类型,平均每个需要修改3个文件共计21处代码
造成的影响
- 用户投诉率上升:退订和续订操作按钮偶发性消失导致客诉增加
- 开发效率降低:新同事接手该模块后首次需求交付延期3天
- 系统风险增加:因状态判断冲突导致错误展示敏感操作按钮3次
问题分析
通过代码考古和埋点数据分析,发现核心问题在于:
- 状态耦合:后端各个组件的状态数据独立维护,导致前端在对相同状态但属性值不一致得情况下,需要开发多套代码
- 渲染策略:每次渲染都重新计算所有操作权限,未做结果缓存
- 代码结构:采用多层嵌套的if-else逻辑判断操作可见性,代码阅读困难
问题如何被解决
面对这个问题,我决定从以下几个方面入手:
1. 协同后端,统计所有的状态枚举值
后端提供了数据接口,我通过与后端开发人员的紧密合作,获取了所有可能的状态值。这一步非常关键,因为只有准确知道所有的状态值,才能进行后续的逻辑处理。通过后端的数据库查询和API调用,我们得到了一份完整的状态枚举列表,这为后续的代码重构打下了坚实的基础。
python
# 中间状态
class VM STATE:
RUNNING = "running"
BUILDING = "building"
SUSPENDED = "suspended"
STOPPED = "stopped"
SHUTOFF = 'shutoff'
RESCUED = "rescued"
DELETED = "deleted"
ERROR = "error"
DISCONNETED = "Disconnected"
UPDATING = "updating"
RESIZING = 'resizing'
REBOOTING = 'rebooting'
REBUILDING = 'rebuilding'
MIGRATING = 'migrating'
DELETING = 'deleting'
STOPPING = 'stopping'
STARTING = 'starting'
CREATING = "creating"
BACKUPING = "backingup"
RESTORING = "restoring"
ATTACHING = "attaching"
DETACHING = 'force_detaching'
ACTIVE = 'active'
SHELVEING = 'shelving'
SHELVED OFFLOADED = 'shelved offloaded'
# 快照创建中
SNAPSHOTTING = 'snapshotting'
# 退订中
UNSUBSCRIBING = 'unsubscribing'
# 已退订
UNSUBSCRIBED = 'unsubscribed'
2. 协同产品需求经理,梳理各种状态的具体功能意义
在得到了状态枚举值后,我与产品需求经理一起梳理了每种状态的具体功能意义。这一步帮助我理解了每个状态在业务逻辑中的作用,以及用户在不同状态下应该看到的操作选项和提示信息。通过与产品需求经理的深入沟通,我将每种状态的功能意义整理成文档,为后续的代码重构提供了明确的指导。
3. 重构该部分代码时尽可能的考虑代码的扩展性、健壮性、复用性
在代码重构过程中,我采用了多种策略来提高代码的质量。首先,我将状态判断逻辑抽取出来,创建了一个状态管理器类,将不同的状态判断封装成独立的方法。这样不仅使代码更加清晰,还便于后续的扩展和维护。其次,我使用了设计模式,如策略模式,根据不同的状态动态选择对应的操作逻辑,提高了代码的灵活性和可复用性。此外,我还引入了缓存机制,减少了重复计算和渲染,从而提升了页面的性能。
javascript
const operationConfig = {
refund: {
text: '申请退款',
disableTip: '已完成订单不可退款',
validate: (state) => /* 校验逻辑 */
},
// ...其他操作配置
};
4. 针对限制提示,改为通用性提示与枚举列表结合
对于操作限制后的提示信息,我进行了整理和优化。对于常见的限制情况,我设计了通用的提示模板,而对于一些特殊的、定制化的提示,则将其收纳整理成枚举列表。在代码中,根据不同的状态和操作,动态选择对应的提示信息。这样既保证了提示信息的准确性,又提高了代码的可维护性。
javascript
// 通用提示
const TIPS = {
UNAVAILABLE: '当前状态不可操作',
TIME_LIMIT: (deadline) => `请在${deadline}前操作`
};
最终成果
指标 | 重构前 | 重构后 |
---|---|---|
代码行数 | 572行 | 127行 |
渲染耗时(50条) | 1.3s | 86ms |
状态扩展成本 | 3人天/状态 | 0.5人天/状态 |
操作提示统一率 | 43% | 92% |
自己的成长
通过这次重构经历,我在多个方面得到了成长:
1. 增强了对项目代码以及公司业务的理解
在与后端和产品需求经理的协作过程中,我不仅熟悉了项目的整体架构和数据流程,还深入理解了公司业务的逻辑和需求。这让我在后续的开发工作中能够更好地从全局角度考虑问题,提高开发效率和代码质量。
2. 提升了协同处理能力
这次重构涉及到多个部门的协作,通过与不同角色的人员沟通和协调,我学会了如何更有效地表达自己的想法,倾听他人的意见,并共同解决问题。这种协同处理能力将在今后的工作中发挥重要作用。
3. 技术能力的提升
在代码重构过程中,我接触到了新的技术概念和设计模式,如策略模式、缓存机制等。通过实践,我将这些知识运用到实际项目中,不仅解决了当前的问题,还为今后遇到类似问题积累了宝贵的经验。
4. 对代码质量的更高追求
经历了这次重构,我深刻认识到代码质量的重要性。冗余、难以维护的代码不仅增加了开发成本,还影响了用户体验。因此,在今后的开发工作中,我会更加注重代码的可读性、可维护性和扩展性,努力写出高质量的代码。
为了避免类似问题的再次发生,我会在今后的项目中提前规划代码结构,加强代码审查,及时整理和注释代码,并与团队成员保持密切沟通,共同维护项目的可持续发展。
总之,这次重构不仅解决了项目中的实际问题,也让我在技术能力和职业素养上得到了全面提升。