「前端开发总结」高效开发,老代码可以这样动

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
.cn 域名,1个 12个月
简介: 日常的工作中,总免不了要改动老代码。之前遇到了几次老代码改动的线上bug,所以总结了一波改动经验,用来做备忘。

前言

一般项目存在2年及以上,代码就会变得臃肿且不好维护。如果有人员变动,新成员加入,可能面临的第一个难题就是,如何在老代码中加新需求。

我之前刚入职,接手老项目,内心活动是这样的:

  • 新功能的添加会不会影响老功能?
  • 工期如此紧张,我还有时间做功能设计吗?要不直接上手码代码得了?
  • 新增的功能跟已有的很相似,我是提公共还是在下面直接粘贴一份改改?如果提公共,原来的功能要不要测试一下?
  • 紧急的线上的bug,但是代码第一次见,今天必须修复上线,时间太紧了怎么办?
  • 业务逻辑太复杂,平时迭代频繁,我有时间捋代码吗?
  • 老的功能不熟悉,新的需求要修改原来的逻辑,但是逻辑挺绕的,交互多,UI还不好实现,我应该怎么排期才合理?

虽然看上去像个戏精,但是句句都是真情实感。接手老项目遇到的这些疑问,不仅实际发生的频率较高,而且很大一部分会影响开发效率和质量。

虽然没有研究出什么武学奥秘「降龙十八掌」,但是我用毕生所学,总结了「老代码的神行百变」。


功能变通

老页面添加新功能,并不是所有时候都会影响原有的功能,所以开发之前做一下功能分类,会有「事半功倍」的效果。

功能隔离

有时候,需要添加的功能点,可能只是一个单选项或者下拉框,这个时候封装个组件也没什么必要。但是毕竟是在老的页面上添加,既要不影响现有功能,又要考虑之后做功能扩展。

我一般会做功能隔离。得益于JSX的灵活写法,封装代码段十分方便。相对独立的功能就不过多说了,这种情况下做功能隔离很简单。主要是有依赖关系的功能,如何做隔离?

其实功能隔离也有点解耦的思维在里面,虽然功能有依赖性,但是不一定要把代码写在一起。

比如产品订单,所有产品类型的订单都在订单管理中,A产品的产品经理说,A产品的订单撤单的时候要给二次确认提示,但是B产品没有这个要求。

我把是否进行二次确认弹窗的逻辑放在了弹窗外侧的列表操作上。撤单弹窗里面中直接对二次弹窗的处理。这样一来,撤单弹窗中的代码不用关心哪条业务线需要进行二次确认操作。外侧的撤单按钮不需要关心撤单弹窗里面是怎么操作的,只需要把控制二次确认弹窗的变量reconfirmFlag(是否二次确认布尔值)传入弹窗即可。

这样,未来如果再加其他的产品类型,只需求维护列表撤单操作代码里面的条件判断即可。

列表撤单操作

record.reconfirmFlag=false;
// =>true: 帽子产品需要二次确认弹窗if (record.type==='hat') {
record.reconfirmFlag=true;
}

撤单弹窗确定操作

/** * 提交操作 * @param {Object} value 接口入参 * @return {void} 无 */consthandleSubmit=value=> {
let { data } =props;
if (data.reconfirmFlag) {
// 二次确认提示  } else {
// 提交操作  }
};

相似功能的提炼

新增的功能和现有的功能非常相似,也是在开发中经常遇到的情况。可能习惯性的或者为了求稳直接把老代码复制一份,修改修改完事。

看似又快又稳的操作,会导致代码变得越来越冗余,老代码变得越来越难维护。

怎么提炼?

相似功能主要有两点,同和异。相同部分是需要提炼的内容。对于差异的部分,我之前习惯用条件判断,现在习惯用枚举的方式。

不同产品分类展示产品信息

/** * 产品介绍 * @param {string} type 产品分类 */constgoodContent=type=> {
constgood= {
hat: {
title: '帽子',
name: '帽子A',
color: '黑色',
    },
shoses: {
title: '鞋子',
name: '鞋子B',
color: '白色',
    },
  };
constgoodItem=good[type];
return (
<div><div>{goodItem.title}</div><div><div>产品名称:{goodItem.name}</div><div>产品颜色:{goodItem.color}</div></div></div>  );
};
return (
<div>    {goodContent('hat')}
    {goodContent('shoses')}
</div>);

不同类型图片展示和编辑

/** * 图片展示 * @param {Array} imgList 图片列表 * @return {void} 无 */constcolImgContent=imgList=> {
return (
<>      {imgList.length!=0&&imgList.map((img, index) => (
<Colspan={4} key={index}><imgclassName='img-block'src={img} /></Col>        ))}
</>  );
};
/** * 图片展示 * @param {string} type 图片分类 */constimgContent=type=> {
constimgObj= {
hat: {
title: '帽子产品展示',
imgList: [],
    },
shoses: {
title: '鞋子产品展示',
imgList: [],
    },
  };
constitem=imgObj[type];
return (
<divclassName='mb10'>      {item.title}<Buttontype='link'onClick={() =>uploadImgs(item)}>编辑</Button><Rowgutter={(12, 12)}>{colImgContent(item.imgList)}</Row></div>  );
};
return (
<div>    {goodContent('hat')}
    {goodContent('shoses')}
</div>);

老功能要不要测?

当然,测试是肯定要测的。不过提测的时间点可能会因情况而异。

我一般在需求设计阶段就会把需要额外测试的地方标注出来。但是有些需求任务量小不需要设计评审,这种情况下如果要增加额外的测试功能点,需要提前跟测试的同事沟通,一般不是翻天覆地的修改,测试的同事是很好沟通的。如果改动影响范围太大,测试的同事要做风险评估之后,才能确定是否可以进行代码改造。

注:可能每个公司的工作流程不一样,请大家参考公司的实际流程进行提测要求和提测操作。

精准定位

线上的紧急bug、临时上线的紧急需求等,即考验开发者的抗压能力,又考验自身的技术能力。有些技术难题,确实需要过硬的技术功底。但是有些问题,找准问题的关键点,其实不难解决。

不是逗闷子,先来看几个例子。

无法唤起的收银台

前情提要

同事离职之后,叶一一暂时接手了同事负责的工作,还没有完全熟悉那部分业务。这天,叶一一拎着早餐来上班,产品经理过来说一个活动的收银台无法唤起了,让叶一一帮忙看一下。

第一次知道这个活动的叶一一是这样做的

虽然叶一一对这个活动非常陌生,好在所有的活动功能都在项目的activity目录下。找到对应的页面,叶一一没有急吼吼的去熟悉业务,她在做其他业务线购买流程时很清楚一点,进行提交操作之后才会唤起支付收银台,所以叶一一先找到提交按钮,然后再去找唤起收银台的代码,发现这个活动的收银台是跳转第三方的,而跳转第三方url中带有test字符的域名,叶一一就知晓了问题所在。

果然不出所料

叶一一问产品,跳转第三方收银台的链接,测试环境和正式环境的分别是什么。拿到链接之后,果然测试环境带"test"线上不带。叶一一加上环境判断区分不同环境的跳转链接,再上线之后,线上就能正常跳转收银台了。

后续

叶一一后来熟悉这个活动功能的时候发现,活动流程还挺长的,到达购买页面之前至少有5、6个步骤。所以,如果叶一一没有精准定位问题,到达购买页面还得费点功夫。

这里可以根据构建命令或者域名区分当前环境,最好能提炼成公共方法

// 区分线上和测试环境的地址letprodEnv=env==='production'leturlPrefix=prodEnv?'https://api' : 'https://testapi';
consturl=`${urlPrefix}.com`;

测试通过之后的线上报错

前情提要

叶一一刚接手了从别的组并过来的项目,还没来得及看代码,就来活了,有大概10个页面需要改动。叶一一看不是改文案就是在原来的基础上新增模块,就愉快的定好排期开始干活。

测试通过

很顺利的开发完功能,自测没有什么问题,叶一一就提测了。测试过程也很顺利,上线日,代码早就准备好,就等晚上上线了。

线上验收

线上验收时,测试的小伙伴发现有个接口报错了,后端的同事说这是一个老接口没有做过调整。叶一一找到出现问题的接口,发现是一个很简单的获取数据的接口,都不需要入参。怎么会有问题呢,测试环境明明没有问题。

「全组的等待」+「就差这一个问题就验收通过」的双重压力并没有让叶一一慌乱。叶一一遇到过多次玄妙问题,只要找准问题关键,不难解决。

正式环境和测试环境唯一的区别就是接口加密,会不会加密的接口需要什么特殊处理?叶一一本地运行加密命令,果然接口报错。叶一一又对比了其他接口,唯一区别就是这个接口没有入参。于是叶一一尝试在入参传了一个空对象,果然接口成功并返回数据。叶一一让后端帮忙看加密的逻辑,确实有特殊的逻辑处理。

后续

后来叶一一发现其他项目没有这个问题,是因为在axios封装时做了特殊处理,新接手的项目没有进行处理。

// 处理过config.params=JSON.stringify(params);
// 未做处理config.params=params;

小结

有些问题,在特殊场景才会出现,这个时候通过对比特殊场景和常规场景的异同,找到不同点,能够帮助快速解决问题。

业务变通

熟悉业务

与其担心不熟悉业务,不好改需求或者评估开发排期,不如抽时间熟悉业务。业务熟悉起来也可以间接的提升开发速度和开发质量。

业务线太多怎么办?

我个人是「好记性不如烂笔头」这一派的。我无法一次记住全部的业务功能,那就写写文档,将功能梳理出来。

如果业务线多,那就一条一条的捋。切记「贪多嚼不烂」,以及避免「迷路蜜蜂」的状态。


单个业务如何梳理?

不同的业务,梳理的侧重点也会有所不同。

  1. 流程较长的业务,需要捋顺整个流程。可以通过绘制流程图的方式,辅助理解和记忆。
  2. 交互复杂的业务,需要新定边框,再细化交互设计。交互是比较分散的,但是类型比较确定,弹层是弹层,下拉项是下拉项。整体的交互风格先定好,可以减少后期的修改。
  3. 内部逻辑复杂的业务,需要拆分层级。先拆成最小颗粒度,再做功能组合,有点像搭积木,先把形状分类好,再搭结构,最终完成「图纸」上的模样。
  4. 偏活动类的业务,梳理文档中,最好列出来活动入口、参与规则(可能会影响前端的功能)、参与记录的查看方式等。

已整理业务文档数量

类型

文档数量/个

产品线文档

12

理赔组业务文档

7

抽离业务组件

先绘制出全部业务模块,分门别类。然后横向对比业务功能,思索今后的发展,确定哪些功能是可以抽离业务组件的。

抽离的本意,一方面提升代码的复用率,不必重复开发;另一方面,可以将复杂功能拆解,便于后续的快速迭代。

抽离的好处,功能写的又快又好,一次开发,造福未来。

我之前写过一篇关于业务组件的思考,这里不展开说了,指路☞【工作小记】关于业务组件的思考

思维变通

设计文档

我的设计文档主要包括三部分内容,开发前准备、开发排期、需求拆分和重点功能设计。

开发前准备

准备的内容主要是功能开发之外的事情。

比如小程序开发是否需要新增业务域名,新增的项目是否需要运维的同事帮忙配置域名,公众号新增页面上线之后是否需要提供入口链接等。这些可以再设计文档中进行记录,避免遗忘。

开发排期

我的开发排期中包含每一项开发需要的具体时间,以页面为维度,以小时为最小的时间单位,然后汇总成天数。实际的开发周期和联调周期,还需要结合手上有没有其他并行的需求和后端同事的开发周期。

需求拆分和重点功能设计

我会把所有的需求罗列出来,避免漏掉哪个。但是功能设计一般只会做重点功能,或者一些组件封装的设计。

重点功能设计主要是处理方案和重点功能代码块,如果流程复杂的会附上流程图;如果状态值较多的项,附上枚举值对应表格。

抽丝剥茧

并不是所有的功能是复杂的,把功能抽离到最小功能,肯定有是简单的部分,而复杂的内容只占其中一角。

比如一个列表页,搜索项和列表展示比较简单,删除操作页很简单。但是新增的表单很复杂。

如果卡在复杂的功能处,不妨先完成简单的部分。如果经常卡在复杂的功能上,就要自我反思一下了,平时有没有做功能整理和技术提升,来帮助自己更好更快的开发复杂功能。

排期变通

正向排期总是失误,不妨试试反问式排期方法。

  • 为什么只是在原来功能中加了一个小需求,但是写的排期却这么长?它难在兼容老功能还是新增的功能?
  • 为什么修改的项这么多,但是写的排期时间却这么短?复杂程度是不是真的不高,不要被想当然坑了自己?
  • 别的页面需要的时间都很短,为什么唯独这个页面需要这么长的时间?它的复杂点到底在哪?
  • 为什么联调的时间反而比开发的时间长?是我联调时间写长了?还是开发时间写短了?还是联调接口太多,参数太复杂?

总结

对于老代码的改动,确实耗时又费心神。所以我有时候会在我的设计文档中,写一些鼓励自己的俏皮话。一定要好玩一点不要太中规中矩,才能逗笑自己的同时,激发干活的热情。

凡事留一线,代码好扩展。

功能设计好,bug见得少。

今天努力捋顺的需求,都是日后宝贵的财富。

目录
相关文章
|
25天前
|
JavaScript 前端开发 Docker
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
在使用 Deno 构建项目时,生成的可执行文件体积较大,通常接近 100 MB,而 Node.js 构建的项目体积则要小得多。这是由于 Deno 包含了完整的 V8 引擎和运行时,使其能够在目标设备上独立运行,无需额外安装依赖。尽管体积较大,但 Deno 提供了更好的安全性和部署便利性。通过裁剪功能、使用压缩工具等方法,可以优化可执行文件的体积。
101 3
前端全栈之路Deno篇(二):几行代码打包后接近100M?别慌,带你掌握Deno2.0的安装到项目构建全流程、剖析构建物并了解其好处
|
7天前
|
前端开发 JavaScript
前端界的革命:掌握这些新技术,让你的代码简洁到让人惊叹!
前端技术的快速发展带来了许多令人惊叹的新特性。ES6及其后续版本引入了箭头函数、模板字符串等简洁语法,极大减少了代码冗余。React通过虚拟DOM和组件化思想,提高了代码的可维护性和效率。Webpack等构建工具通过模块化和代码分割,优化了应用性能和加载速度。这些新技术正引领前端开发的革命,使代码更加简洁、高效、可维护。
11 2
|
7天前
|
前端开发 JavaScript 测试技术
前端工程师的必修课:如何写出优雅、可维护的代码?
前端工程作为数字世界的门面,编写优雅、可维护的代码至关重要。本文从命名规范、模块化设计、注释与文档、遵循最佳实践四个方面,提供了提升代码质量的方法。通过清晰的命名、合理的模块划分、详细的注释和持续的学习,前端工程师可以写出高效且易于维护的代码,为项目的成功打下坚实基础。
15 2
|
12天前
|
监控 前端开发 JavaScript
前端开发的终极奥义:如何让你的代码既快又美,还不易出错?
【10月更文挑战第31天】前端开发是一个充满挑战与机遇的领域,本文从性能优化、代码美化和错误处理三个方面,探讨了如何提升代码的效率、可读性和健壮性。通过减少DOM操作、懒加载、使用Web Workers等方法提升性能;遵循命名规范、保持一致的缩进与空行、添加注释与文档,让代码更易读;通过输入验证、try-catch捕获异常、日志与监控,增强代码的健壮性。追求代码的“快、美、稳”,是每个前端开发者的目标。
29 3
|
14天前
|
前端开发 JavaScript 安全
揭秘!前端大牛们如何高效解决跨域问题,提升开发效率!
【10月更文挑战第30天】在Web开发中,跨域问题是一大挑战。本文介绍前端大牛们常用的跨域解决方案,包括JSONP、CORS、postMessage和Nginx/Node.js代理,对比它们的优缺点,帮助初学者提升开发效率。
38 4
|
14天前
|
前端开发 JavaScript 开发者
前端开发的终极技巧:如何让你的代码既简洁又高效,还能减少bug?
【10月更文挑战第30天】前端开发充满挑战与创新,如何编写简洁高效且少bug的代码是开发者关注的重点。本文介绍五大技巧:1. 模块化,提高代码复用性;2. 组件化,降低代码耦合度;3. 使用现代框架,提高开发效率;4. 统一代码规范,降低沟通成本;5. 利用工具,优化代码质量。掌握这些技巧,让前端开发更高效。
29 1
|
1月前
|
负载均衡 前端开发 JavaScript
前端研发链路之开发
本文首发于微信公众号“前端徐徐”,作者徐徐。文章介绍了前端研发链路中的开发部分,重点探讨了开发服务器(dev-server)、热更新(hot-reload)、数据模拟(mock)和代理(proxy)等关键技术,帮助开发者理解其基本原理和应用场景,提升开发效率和代码质量。
36 2
前端研发链路之开发
|
21天前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
28 1
|
1月前
|
人工智能 前端开发 测试技术
探索前端与 AI 的结合:如何用 GPT-4 助力开发效率
本文介绍了 GPT-4 如何成为前端开发者的“神队友”,让开发变得更加高效愉快。无论是需求到代码的自动生成、快速调试和性能优化,还是自动化测试和技术选型,GPT-4 都能提供极大的帮助。通过智能生成代码、捕捉 BUG、优化性能、自动化测试生成以及技术支持,GPT-4 成为开发者不可或缺的工具,帮助他们从繁重的手动任务中解脱出来,专注于创新和创意。GPT-4 正在彻底改变开发流程,让开发者从“辛苦码农”转变为“效率王者”。
31 0
探索前端与 AI 的结合:如何用 GPT-4 助力开发效率
|
1月前
|
前端开发 JavaScript 开发者
利用代码分割优化前端性能:高级技巧与实践
【10月更文挑战第2天】在现代Web开发中,代码分割是优化前端性能的关键技术,可显著减少页面加载时间。本文详细探讨了代码分割的基本原理及其实现方法,包括自动与手动分割、预加载与预取、动态导入及按需加载CSS等高级技巧,旨在帮助开发者提升Web应用性能,改善用户体验。