前端代码0bug经验分享

发布时间 2023-04-07 15:45:49作者: 行走的蒲公英
  • 如何写好代码其实是一个很大的话题,本次仅分享一些自己的经验之谈,有其他idea的欢迎交流
  • 在我看来,写好代码更多的是逻辑思维的体现,而这,紧靠一两次分享是无法提高的,我只能尽可能的将可能可以复制的经验进行分享
  • 本次分享不会涉及太多你使用的框架的具体使用细节,技术选型总是千变万化的,我们需要的是抓住不变的部分
  • 更希望大家多去锻炼逻辑思维和学习一些编程方法论,毕竟编程语言只是工具而已
  • 当然,经济基础决定上层建筑,技术基础和上层框架本身也是很重要的,这个就留待各位自行求索了

开发前

一、项目

  1.掌握(注意是掌握而不是了解)你所开发的产品的主要功能点和核心功能点,作为研发中与客户最为接近的环节,可以称得上是公司门面的一部分,前端务必要对产品有深刻的理解 ——

(1)产品定义

(2)各个主要功能点和核心功能点的数据的来龙去脉(后台的时序图及前端对应模块涵盖哪些)

  

2.了解后台架构,若是微服务的话,思考或和后台同事探讨各个服务的职责范围,了解一些常见中间件的作用

    问一个小问题,你知道项目中的图片是如何存储的吗

  3.掌握项目主要功能模块的代码

    • 路由设计
    • 登录、用户权限设计
    • 数据分层 —— 如请求层(各个interceptor作用)、适配层、业务层
    • 通用业务代码 —— 是否有通用组件、通用hooks、共用type等
    • 配置项代码
    • 各个业务模块代码

  4.技术栈

    • 至少了解每一个技术出现是为了解决什么问题、怎么解决的(不需要看源码,看它暴露的api就好了)
    • 了解每一个技术的核心思想,如react就是一个data驱动的UI框架、redux就是一个单向数据流的状态管理工具

二、需求评审

1.尽可能早的介入

    • 可以实现的能否做得更好
    • 可能可以实现的提前预研、出demo等
    • 不能实现的或者交期无法满足的商量让步方式

2.剖析需求

    • 了解产品(非产品经理)真正的需要是什么 —— 现场(客户)的需求是什么、是在什么场景下提出的、最终是要解决什么问题,同时可以帮助产品经理和测试经理梳理该需求的核心到底是什么 —— 有时候确实三方理解会出现偏差,但核心把握住,一般后期修改也相对容易些,不至于重构
    • 结合项目实际情况,分析需求的来龙去脉 —— 数据需要怎么进来(一般是在设置\任务中)、进来后怎么展示(数据展示页、是否有实时消息等)、是否需要增加权限相关边缘功能等、考虑该数据增删改可能带来的影响有哪些
    • 该需求是否会对原有的功能有影响,可调和的 —— 可能可以做合并操作,不可调和的 —— 需要提前同产品经理、测试经理确定如何处理,替代or保留
    • 感兴趣的话,可以和后台同事聊一聊他们的设计、表结构、数据流

3.UI评审

    • 从上到下,从左到右,事无巨细的浏览一遍,对于其要实现的主体功能有个把握
    • 基于主体功能在脑海中快速过一下可能的开发设计方案
    • 再考虑分支功能可能需要往刚刚的设计方案中增加些什么,是否需要重构设计方案
    • 是否存在矛盾或者难以实现的功能点,及时提出调整
    • 在屏幕适配上是否满足目前产品的主要需要(满足1366 * 768及1920 * 1080),当前设计稿基本都是基于1920 * 1080来的,对于一些内容繁多的页面来说,可能不好适配1366 * 768,需要及时商量如何调整或进行额外布局适配工作
    • 上述过完后,需要过一遍用户如何使用的场景 —— 评估功能易用性、评估未显示在页面上的额外交互的空白地带、同时看是否需要修正自己的设计方案

三、开发设计

1.组件设计

(1)组件拆分

 非必要不拆分,大部分情况下建议先写代码,然后视情况做拆分工作 —— 在如下几种情况下建议拆分

    • 多处共用   非UI相关的,建议抽成通用hook进行维护
    • 业务逻辑较为复杂导致占据该文件的大部分代码,证明该部分代码内聚性较高,考虑抽离
    • 单文件代码超过400 - 600行

(2)可否复用现有组件或hooks

    • DRY —— Don't Repeat Youself

    • 完全一样功能的,直接复用,后续也便于统一修改

    • 有点出入的,考虑略微修改以实现调用方的兼容

      经过多次扩展后,若一个组件出现了10个以上props或者内部已经一堆的if else了,务必及时再次审阅拆分开来

    • 有较大不同的,但又有不少相似的,建议copy一份另外做个组件

      api请求函数,见过太多反复编写的了,对于接口层,动手前搜一下,看是否存在了,若存在,优先复用,一是节省时间,二是中心化便于后续可能的修改

2.数据设计

          当代前端应用开发的核心就是做好数据的管理 —— 增、删、改、查

(1)state

(2)props

(3)衍生数据 —— 保证state或者props的精简和纯粹性

(4)redux or context —— 多组件共用的,优先考虑提升到父组件,只有当共同的父组件不属于该业务范畴或者很远时才考虑使用

(5)受控 vs 非受控,对于antd form组件,非必要不受控、直到某个form item不受控就无法满足业务需求时再考虑受控

  可能的话,统统单一数据来源,尽量避免某个渲染状态是多个相似数据的复合结果,状态越少越好

3.交互设计

    • 多浏览一些交互比较OK的网站,包括但不限于各个知名UI组件库、各个大公司相关产品的官网,培养自己的审美及增加对于何谓好交互的积累
    • 多站在用户角度进行考虑,他们会如何使用这个功能点,是否需要增加一些提示性的交互,如cursor: not-allow提示某些功能暂时被禁用(这种的话需要同时注意是否只实现了css,漏了js的事件了)

开发中

一、自顶向下编程

先主干,后枝干

import ModuleStyle from './index.module.scss';

function Page() {
  const [shareData, setShareData] = useState(0);
  return (
    <div className={ModuleStyle['page']}>
      <Component1 data={shareData} />
      <Component2 data={shareData} />
      <Component3 data={shareData} />
    </div>
  );
}

这里可以把外层框架搭好,如整体layout,不同组件间需要共享的数据管理等

提一嘴,css建议务必采用module css或类似方案(如styled components),否则容易覆盖

import ModuleStyle from './index.module.scss';

function Component1(props: {data: number}) {
  const [data, setData] = useState([]);
  return <div className={ModuleStyle['component1']}>...</div>;
}

联调前,可以先把静态页面做好,有时间的话,增加处理下加入异步请求(可以考虑自行使用setTimeout模拟或者自建mock服务)后的四种常见状态 ——

    • 请求前
    • 请求时
    • 请求后

主干完成后进一步处理分支功能 —— 如是否需要根据props做一些重新请求或者重置的操作、或者要查询条件变更的处理之类的

联调时依旧要把主干功能和分支功能过一遍,同时注意下后台数据的校验处理,防止reference报错

二、react等

  如下几个核心个人认为需要完全掌握

  • 官方文档

  • 近一两年的一些比较重要的版本更新我都会去拜读一遍

  • 工作流及类组件的生命周期

  • setState

    • 同步、异步,建议了解下底层原理
  • 合成事件

    • 原理及可能的坑
  • hooks心智模型

    “忘记你已经学到的。” — Yoda

  • Hook API 索引 – React (reactjs.org)

    useEffect 完整指南 — Overreacted dan大神的博客,建议订阅

  • 类组件何时实例化、何时会调用render、函数组件何时被调用 —— 重点,建议深入理解

  • 警惕反模式,若使用中出现了反模式,那大概率会出现问题

    凡是可能出错的事就一定会出错。 —— 墨菲定律

    举两个例子

    • 破坏react props不可变更的原则,在子组件中自行修改props

       

破坏redux的数据更新必须通过dispatch action来进行的原则,自行随意修改某个属性

 

三、良好的命名和注释习惯

代码是写给人看的,不要以为自己能看懂就行,大部分人在两个月后将不知道自己曾经写了些什么鬼东西

  • 优先考虑命名和类型即注释,不要担心名称过长,react还用了getDeriveStateFromProps这么长的名字,但通俗易懂

export function getEventList(cameraIds: number[]) {
    // balabala
}

       

警惕,不仅是函数名,变量名也要注意,见过太多data1、data2这种你不深入看都不知道干啥的,还有尽量避免leftList、rightList,这种可能跟UI布局挂钩的,有一天左右切换,直接让你疯狂

推荐名称与业务挂钩,如getExconvictUnregisteredList —— 获取未登记前科人员列表

  • 对于名称较难解释,或者还需要有必要说明的,使用JSDoc规范注释,vscode原生支持,简单的输入/**回车即可
/**
 * 该函数的功能描述
 *  可以附带上大致的实现说明或者使用的注意事项
 * @param a xxx参数
 */
export async function somethingHardToSay(a: number[]) {
  // balabala
}

      

  • 对于一些不符合常识或者难以理解的务必要注释

  • TODO WARN 等标记

再结合第三方插件(如Todo Tree - Visual Studio Marketplace),在转测前可以过一遍自己开发的功能中是否有相关标记需要注意的

四、善用工具

1. 第三方库包

    前端react社区中已经有很多轮子,建议优先搜索使用,需要注意通过多个信息来决定是否使用,即使最后定论不使用转而自己实现,也可以学习下它的设计思路并规避其缺陷

    比如说你需要一个拖拽排序组件

 (1)搜索及选择

  google search first,最好英文搜索,react drag and sort

            

查看前几个一般就够了,到对应仓库查看更多信息,如react-dnd

重点关注如下几个信息:

1)项目使用数,个人觉得1000+就值得考虑尝试了

        2)版本发布信息,最好是还在持续维护的(如近一年还在更新的)

            

(2)加分项

1)文档健全

2)使用ts编写(可以免于下载@type文件,或者类型文件与源代码版本不匹配问题)

   (3)更多

1)善用npm trends: Compare NPM package downloads,极力推荐

    特别是当遇到一些搜到的库包质量不是很高时,可以考虑用这个搜下,然后有一个related的列表,里面一般是一些相似工具的比较,比较容易挖到好东西。

2)直接在github中搜索

3)持续关注一些高质量的前端输出者,如关注一些公众号或订阅其博客等

4) 社区精选组件 - Ant Design

5)不仅仅是UI组件,hooks生态也在逐步完善,多从streamich/react-use: React Hooks — ? (github.com)ahooks - React Hooks Library等知名hooks库中挑选,一些常见场景早就有比较完善的解决方案了,不要再造可能有不少bug的轮子了。推荐一波ahooks的useRequest。

2.宇宙第一IDE

   实用功能推荐

    • 查找引用,shift + alt + f,甚至类型的属性的引用也能找出,对于没有严格lint的项目而言,简直就是福音

  插件

    • 上文提及的TODO Tree

    • Search node_modules,对于一些可能是源码的错误,且源码开源的话,能很方便找到

    • GitLens — Git supercharged,快速查阅行、文件变更,行提交记录实时显示

  浏览器插件

               

2.单组件在本次profile中被记录了几次commit

       3.这次update可能是由什么引起的(试验性功能,可能有部分错误,但已经基本可用了)

      

五、开发后

代码审阅

  • 自己审阅已开发完的代码
    • 是否存在功能性缺陷、是否存在性能性缺陷
      • 前者评估其严重性,若是严重类,需要在转测前将其改掉,否则视交期安排酌情考虑是否变更
      • 后者若可以快速优化的,则立即优化,否则在相关代码上加个TODO/WARN之类的标识,便于后续优化
    • 没有问题的前提下,看是否有更好的方案,若该变更可在转测前完成,建议修改,否则可以自行总结在小本本上,下次类似功能尽量避免
    • 各类边界条件审阅
    • 控制语句审阅(switch case、if else),是否有未考虑到的case,该case是否会影响功能
  • 有条件的话,同事间相互审阅

冒烟用例

尽可能详尽的过一遍冒烟用例

  • 冒烟用例一般是一些主体功能的提炼,若不能通过的话,本次开发就不算成功的,需要修改
  • 代码最终实现可能和测试的测试方法有出入,需要三方对齐,如果你觉得自己的更有道理,完全不用改,尝试去说服产品跟你站在同一阵营,人人都是追求更好的交付的;若自己确实做得有问题,时间允许的情况下建议及时修改,否则需要同步相关信息到产品、测试、开发经理,评估严重性,再做进一步的计划

bug解决

  • 定位bug原因
  • 评估影响范围
    • shift + alt + f,查找相关引用,可能还有引用的引用等,需要查找全
    • 评估对使用方的影响,需要兼容处理的做兼容处理,需要当bug处理需要进行变更,所有有变更的地方做个记录
  • 禅道单点解决时,附上影响的功能点及建议测试方法,或者私聊对应的测试同事也可,务必要cover all
  • 扩展
    • 横向 —— 在其他地方是否有类似问题,若有类似问题,并且是产品的核心功能点,建议协同测试一并解决掉并做记录
    • 纵向 —— 引发该问题的更深层次的原因是什么 —— 如深入源码、推动第三方库包解决(有时间的话甚至可以尝试解决并提个pr)等
    • 未来 —— 以后如何避免、是否要做成典型在组内分享