最近在做注册模块,有一个步骤是输入邮箱点击发送验证码按钮,补全收到的验证码和其他的信息后即可完成注册流程。没想道在验证码这块出现了多次问题,并且修改多次,这让我陷入了深思。
发送前的准备工作
其实发送验证码之前是有一些前置条件的:
- 邮箱必须符合要求,如果输入的是无效或者格式错误的邮箱是无法发送验证码的,这一步前端控制
- 邮箱必须未注册过本平台。
第一步前端通过正则表达式即可判断。第二步需要请求后端的接口来获取输入邮箱的注册情况,这是一个异步操作,后续的发送调用需等待前一个异步操作完成后再进行。
而邮箱的检查时机是在用户输入邮箱时触发的(input),为防止频繁检查,我得意洋洋地做了个防抖操作:
let Timer = null;
const makeTimer = (emailCheckfn) => {
clearTimeout(Timer)
Timer = setTimeout(()=>{
emailCheckfn();
},300)
}
element.addEventListener('input',()=>{
makeTimer(APICallFn)
})
而,我们并没有做检查调用的状态记录,并且由于可能发起多次异步请求,这些并行的异步请求在网络波动下触达前端的时间不一定遵循发起调用的时序,需要留意最近的一次检查,头大!
如果按照这个路子走,需要等待对于这个小问题要考虑的点太多了,是不是哪里不对?
程序的边界
想到一个产品同事讲到一句话:程序应该定义好边界。
当时听完只觉得是一句正确的话,没有什么特别之处,今天感触就比较深了。
上述问题来源于便捷模糊
从开发(我)的角度来讲,开发希望能在用户输入后立即响应(检查),让用户感到程序非常的快。 然而这给开发增加了很多的心智负担,这些负担会显著增加程序出bug的概率。
跟产品讨论后确定了边界: 只在发送点击那一刻去检查输入邮箱的注册情况,如邮箱未注册触发发送,已注册则提示用户。 如用户重新输入邮箱,删除之前的提示。
这样就可以在点击时将 检查和发送做串行操作了。复杂度大大减少。
除此之外,还有?
其实出了上述提到的,还有程序的异常处理,有些程序员(比如我)异常也不处理,导致控制台各种错误信息泛滥,一些后端程序员动不动直接将程序处理失败的堆栈信息抛给前端(500错误)。
这都是很不好的做法,因为程序应该有始有终,每个程序都是一台人机交互界面:
- 有指令有结果
- 有请求有响应
- 有开始有结束
任何异常情况都应该被合理地处理后反馈结果给用户。
总结
本文通过一个因对“验证码”场景认识不够引发的程序边界问题做了分析例证(扯淡),结论是:程序员的自我修养很重要。别贱看自己,你可是一个人机交互大师。