最近在开发中踩了个大坑,常言到:失败是成功之母。所以在这里总结一下这次的经验教训,告诫自己。同时,也对自己近段时间遇到的开发问题进行总结。
血的教训
问题大致是因为接收其他部门的需求,然后因跨部门沟通协作的问题,踩了个大坑,分锅稍后,先总结下自己出现的问题,下次避免
沟通需求,我们一般都是和PM对接,但在跨部门或者和你不熟悉的项目组对接需求时,你绝对不能只和PM过需求,一定要和他们的开发也过需求,而且是要详细到需求具体实现方式的过一遍,不能只是熟悉代码问一下代码上的疑问。因为可能会有其他的隐式规范在,如:
-
PM与开发间的默契
一般PM与开发在需求对接时会有一些默认的规范,这些规范PM会认为你已经知晓,这你就必须和开发(你新接需求项目的)详细对接需求,询问规范,以及避免下面这种默认的坑:
比如这次,两张图放一起,没有任何标识,看上去完全不相关,只能位置近了些,其中一张是另一个功能后续功能的某一步图片,就表示这一张图后续也要和那个功能点一致,我....
-
沟通要注意需求是否与现有代码实现逻辑有冲突
这一点大家在需求评审时都会注意到,不然等产品验收在看到问题,一旦重新设计,那就白干了,但跨部门时,他们的需求、项目,你接手开发,他们可不一定会帮你把好这一关,所以,一定要在需求对接时问清楚,尤其是涉及的修改范围非常广且杂乱的
-
信息及时周知所有人
在需求修改沟通时,不能认为沟通的人就是负责人,只与他沟通确认,还需与整个需求的其他的沟通,因为如果需求中有另一个人对沟通的这一点产生疑问且其认定解决方式与此人不同,就会产生误解与疑问,找你的问题
有时候与你沟通的人A并不能负责,只是他一个人的看法,哪怕是对的,也会有其他人B认为会对他造成困扰,但由于你没有及时沟通,后续B一直找你关于这个问题,但你认为这个已经和之前沟通的人 A 说明,但找不到A或者A说这个也不是他说的,是你理解错误,这口大锅,就归你了;或者B也不积极,但只是认定这个得解决,但你认为之前已经解决,这个又卡住了,导致延误又是你的锅
所以,我及时周知信息,及时上述的A与B有疑问,也是他们之间pk,就不会首先来K你了
开发经验个人总结
代码逻辑拆分
拆分组件,不要全放在一个文件里,显得代码又乱又杂,这个道理大家都明白,下面是我个人的经验总结
-
在一开始确定需求后就要确认一个大体架构,确认整体结构层级
如 Data 数据源、State 状态管理、View 展示组件,这三层之间的管理,这一步一般都是根据先有项目的实现方式进行调整的,与项目统一 (可以写个思维导图理一下需求逻辑)
-
确认大致状态State,以及是否可以拆分独立hooks,以及对应的View组件怎么拆分
如一个展示 ICON 有多种状态,那么这些状态展示是共享一套组件,还是拆分才显得结构更新清晰;以及简单的展示组件大致可以拆分成多少个
// 可以大致写一下,占个位置,理一下代码结构,再实际开发 const Example = () => { useInitStore(); useMonitorState(); return ( <> <FloatIcon /> <ContentWrap /> </> ); }; -
然后在开发时,有意识的按照自己之前的划分 Code,在 code 过程中,在按照实际情况拆分逻辑 hooks 与展示组件
-
最后自测完成,自己在仔细 review 一下,看看那些是之前没有想到的,现在有更好的解决方法
拆分注意事项
-
拆分要有依旧,要功能解耦、结构清晰
在拆分代码时,要时刻牢记一点:为什么要拆?我们拆分代码总要有一个目的,或者为了区分来源,或是因为同一个功能点,不能为了拆分而拆分,那样只会把代码拆的稀烂,难以维护
以props属性为例,我们可以把部分props属性整合到一起,避免在使用组件的时候传入过多参数导致代码很难看,那我们在整理是就需要根据属性的功能关联、来源来划分,避免最简单的划分从store中获取的,从外部传入的。
type Props{ ownProps: Object; // 外部传入属性 storeProps:Object; // connect 传入属性 } -
拆分要一开始就进行
有时候,我们喜欢把 Code 先放在一起,便于查找,后面在慢慢拆分(比如作者);但这样很可能会导致写的时候把不同逻辑交叉到一起,严重耦合,导致你后续来拆分还不如重新构建实现方案
团队协作注意
每个人都有自己的一套 Code 规范,我只讲述一下团队协作时,我们应该注意的点
单一功能文件
无论是常量 constant 还是 API 或 Thunks 函数,在存放的时候要注意同一功能的常量或函数放在同一文件中,用文件名描述功能 这样结构清晰,后来者一眼便知道文件功能,便于使用和后续维护,这一点在团队开发中很重要,不然,到后期一个文件上千行?找的眼花缭乱...
# 下面两种方式一个全在constant中,一个按功能拆分,结构一清二楚
constant.js
Packet.js
FloatIcon.js
函数&变量命名注意
变量名称的主要作用是告诉开发者:它是什么?为什么存在?如何使用? 所以,我们在给变量命名时,要注意一下几点:
- 名称能真正体现功能作用
- 与其他相似名称要有真正有意义的区分,如一个 string,一个数组,可以使用 s 或 list 区分
- 命名不要有多种含义,避免造成歧义
- 命名词汇要选常用的,不要用生僻词
- 与项目命名规范统一(如驼峰)
避免误导(如:多余的类型转换)
在团队开发时,要注意不要对后续维护者造成误导,就好比类型转换,如果一个变量为 Number 类型,那么对它使用+(转 Number 类型),那么对于后续维护者而言,他第一眼看到,一定会认为这个变量有可能是 string|number 或其他类型,从而对部分代码逻辑的修改产生误判;因此,如果在团队开发时,在类型十分确定的情况下,尽量避免使用冗余或者只是以防万一的类型转换
善用注释
在上述的命名中如果实在无法想到很好的名称,或者代码中有一段比较复杂的逻辑,可以使用注释写明。
但要注意:注释要简明扼要,不要写废话或无意义的注释
// 1: 初始(默认) 2: 结束
const status = 1;
// 这是ID ??? 不要写无用的注释
const id = 1;
代码简洁
除了不要写无用的注释外,冗余或者无用的代码也要尽早删除,不然后续维护者也不敢删除,会导致无用代码越来越多(说不定到后面你自己都不敢删除-_-|)
开发问题总结
状态修改必须可控
下列例子中的 updateState 就是不可控的,每次修改 state 触发 render 都会重复执行,很难控制执行次数,很容易触发未知的 bug,如 updateState 如果是修改时间状态计时的,那么一旦有未知的 store 触发的导致的 render,那边时间状态就难以管理
const Example = () => {
...
const renderState = () => {
updateState();
// 最好放在useEffect中控制,抽离renderState为组件更清晰
// useEffect(() => {
// updateState()
// }, [])
return <div> {state} </div>
}
return <div> {renderState()} </div>;
};
解构时 undefined 状态处理
下列代码中 b 为 undefined 时也能正常替换 state 的 b 的值,不要与Object.assign({}, null, undefined)不处理 undefined 与 null 混淆
手机抓包查看日志时,有些工具自动过滤
undefined字段不显示,导致 bug 好难找...
const state = { a: 1, b: 2 };
const newValue = { a: 2, b: undefined };
const newState = { ...state, ...newValue };
const newState2 = Object.assign({}, state, newValue);
单一逻辑状态
意思是每一个 state 的值,只用来表示一个逻辑状态;不如代码很容易在极限情况出现 bug
# 描述:一个倒计时领奖组件,有两种逻辑状态(倒计时状态[剩余时间]与领奖状态[不可领取、可领取]),领完组件之间消失,即没已领完状态,倒计时状态用户离开需保存
# State:remainTime:剩余时间
# 场景:那么我们可以只设置一个state来处理(remainTime),这样不是简便很多吗
是的,我走一下上述流程,倒计时领奖,remainTime为0之后直接领奖,领完组件消失。恩恩,很正常的流程。
但如果遇到用户倒计到0,但他直接离开了,那么,他下次进入页面,组件展示那种状态,根据 0 我并不清楚,他到底有没有领取,
所以这样就需要另一个state(status: 领奖状态),在判断状态时,我们直接使用status,这样就避免了0的情况
当然,这是一种比较明显的情况,但一个state表示多个逻辑状态时,你无法确定在遇到极限值情况不出现bug,所以保证一个state只表示一个逻辑状态
坚守 Code 风格
每个人都有自己的好的编程风格与习惯。但在时间紧迫或者压力巨大时,风格又是否会变形呢?
比如在开发时间紧急时,或者说需求 delay 了,产品、leader 都在催,让你有一种紧迫感,压力巨大时,能否保持Code风格不变形,不然在 Code Review 阶段,其他人不断提出的 issue,会让你感觉很难受或者是陷入改与不改的争议(我:不改,改了需求要继续 delay; Reviewer: 不改难以维护,看着难受,改...Φ 皿 Φ)
当然时间成本的冲突只能自己评估,但在压力之下保持自己良好的心态,无论对工作Code,还是对生活都是非常重要。
惟有幸福与健康真正属于自己!