修复缺陷的正确姿势
如何修复一个缺陷 如果给我一个小时来修复一个缺陷,我会花50分钟来写测试,用剩下的10分钟来改代码 – 本来是一句模仿爱因斯塔的名言,结果发现爱因斯坦并没有说过…… 你确定这是个缺陷吗? 下午2点,你喝下了一杯拿铁,它可以保证你在接下来的几个小时内保持清醒。突然,一位QA同事急匆匆的走了过来,从他的表情你就看出来事情不妙。果然,他告诉你SIT环境有个重大缺陷,如果不及时修复,好几个测试流程都不能进行。没错,你在还没有完全搞清楚发生了什么值钱,就莫名其妙的突然变成为了系统中一个“blocker”。 这位QA的神情和他对事情的描述让你不自觉的受到了一些感染,你也开始有点焦虑。你想要快速切换到IDE下,赶紧复现并修复他描述的问题。毕竟,你可不想成为一个阻塞别人工作的人。 我对你急切的心情表示理解,不过在你实际动手改代码之前,先冷静一下,稍微抑制一下赶紧修复问题的那种冲动。我们来看看在面对如此场景,如何表现的更为专业,以及更加卓有成效。 开始之前 事实上,在开始修复任何一个缺陷之前,你需要确认它确实是一个缺陷。这一点经常为很多新手忽略,从而导致修复缺陷从艺术变成了救火工作。 作为一名靠谱的开发,在真正动手修复之前,你可以做这样一些预先的check: 缺陷是不是发生在不受支持的浏览器上? 部署之后,有没有清理浏览器缓存? 下游系统是不是有计划内更新? 确定部署了最新版本吗?(部署之后,有没有机制可以确保SIT是最新版本) 或者你可以当QA宣称他找到了一个缺陷时,你可以反问:“你有没有试着重启浏览器/系统?”。很多情况下,在做了这些检查之后,你发现问题自己就解决了 – 此谓不战而屈人之兵也。 如果事情仅仅到这一步就结束的话,你就可以接着看看medium上的文章或者刷刷知乎什么的。不过有时候,事情就不会这么顺利了。 遗漏掉的需求 不论前期分析的多么完善,在实际项目的行进中,还是会遇到一些遗漏掉的需求点。比如招聘系统中的对留学生通道的考虑,银行系统中的海外信用卡的货币汇率转换等等。有时候,当听完QA的描述后,如果你和团队里的其他人都表示这个功能点是第一次听说,那么不用慌张,这很可能是一个被遗漏掉的需求。 这时候只需要冷静下来,将其记录下来,然后作为正常的Story流程进行即可(排列优先级,kick-off,被拖入in-doing等等) 还真是个缺陷 如果它竟然还不是一个漏掉的需求,承认自己写的代码有缺陷也不是什么丢人的事儿。而且即使是缺陷,也并不意味着需要立即修复。和所有的其他需求那样,缺陷也应该被分级,并当成一个正常的Story卡流入Backlog。 在实践中,我发现这一点非常关键。很多团队在开发过程进入修复缺陷阶段之后变得各种混乱,其源头也正是来源于此。一个非常糟糕的实践是:某个人负责将测试团队中发现的缺陷分发给指定的人,并一天两次的常规Check是否有所进展。这个貌似高频率反馈的过程可以毁掉团队的敏捷氛围:工作从拉动的方式变成了指派。 正确的做法是:为缺陷建立卡片,并和其他需求卡一起排列优先级,并通过拉动的方式流入开发流程,并像任何一张卡片那样进行kick-off,in-dev,sign-off等。换言之,不要特殊对待缺陷,把它当成普通的需求变更即可。 如何重现 一旦你确定了一个缺陷,并且需要修复它,那么第一件要做的事情自然是重现它。很多时候,重现并不那么容易。在实际项目中,应用可能有各种各样的外部依赖,比如: 依赖网络请求来获取数据 依赖特定的浏览器(可能是旧版本,也可能是特定浏览器) 依赖后端服务正常工作 所有的后端服务的异常都可能导致前端页面上的非预期行为:一个空白页面或者一个有着大红色叉的对话框,上书“找不着对象”等等。这些错误有时候可能会很难复现,或者至少需要一些特别的设置才可以使之发生。 网络异常 网络异常非常常见,而且可以导致各种各样的异常行为。开发中,localhost或者办公室的千兆宽带往往很难看到一些仅仅会在4G或者更慢速网络中会出现的问题。而当多个页面请求中的某一个失败时才会出现的缺陷则更难以复现。 不过,Chrome提供的DevTools可以在很大程度上帮助你(不过你可能需要每隔一个月重新学习下这些Tab的布局和新功能,Chrome的开发团队非常乐于偷偷给DevTools上线一些新功能,并完全破坏掉之前的布局)。 假设你需要调试/复现一个关于loading控件的问题,这个缺陷仅仅在网络极差的情况下才可以复现。你可以使用Chrome自带的throttling来模拟这种极端的网络场景。而有时候,你需要模拟网络完全不可用的状况,可以勾选Offline. 除了这些常规操作之外,你可以以定义黑名单的方式来屏蔽掉一些指定的URL: 这样,发往黑名单中的URL被屏蔽,这样可以很方便的模拟出改服务不可用的场景。有时候,如果你在开发海外的站点,也可以通过屏蔽特定的URL,比如facebook或者twitter链接来查看该站点在国内的表现。 消除重现缺陷的其他blocker 现实中,大部分实际应用都有多个页面。如果缺陷在第N个页面上,而你每次都需要从第一步导航到第N步。而如果每一步都有一些必填字段要填写,那么要重现这个缺陷,特别是debug的时候就会变成一场噩梦:你修改了一行代码,live-reload自动刷新并将你重定向到第一页,然后你完成所有填写并到达要调试的组件,然后发现本应该是字符串的地方显示的是[Object Object]。 不过,如果你恰好使用React+Redux组合的话,Redux Devtools Extension可以节省你很多时间。通过使用这个插件,你可以将应用的状态导入/导出。 Setup非常容易,只需要在创建redux store的时候加上一行代码即可: const store = createStore( reducer, /* preloadedState, */ window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() ); 这样你可以使用该插件将应用在某一时刻的状态导出到本地文件。在导出的文件中,redux-dev-tools会将应用的初始状态和所有发生过的事件(以及事件相关的数据)记录下来,以便重新播放。 当然了,如果你并没有使用React+Redux的组合,很多表单的auto-filler也是可以完成类似动作的。你可能需要花费几分钟来学习如何定义selector以及如何用快捷键来自动填写,不过一旦学会,它就可以节省你很多时间。 寻找根因 根据我的经验,很多缺陷都并非发生在逻辑错误上(比如倒置的if-else,没有跳出的while等)。相反,很多时候错误会发生在错误的mapping,空值的保护不足等场景。 非法数据 实际应用中,每个集成点都潜在的会有这样的问题。比如UI到BFF,BFF到下游的系统等。代码中的很多配置,或者不一致的惯例也会导致类似的问题。...