以前听过过一个有趣的说法:不要编写没有明显bug的代码,要去编写明显没有bug的代码。这里提到的两个概念:“没有明显bug的代码”和“明显没有bug的代码”。同样的文字,只是调换了下顺序,表达的就是完全不同的概念了。前者“没有明显bug的代码”大概是最常见的代码了,特征就是:

  1. 每段程序看起来合理,但结果就是不对
  2. 程序看起来复杂、奇怪,但就是可以正常运行
  3. 天书一般的程序
  4. 待补充

平时工作中到处缝缝补补的代码大概就是这种代码吧。背后的原因一般比较复杂,有时还不可追溯,项目工期紧,人员交接等等都有可能。因此,与其思考“如何避免没有明显bug的代码”,还不如思考“如何写出明显没有bug的代码”。本文就何为“明显没有bug的代码”总结一些个人的思的胡思乱想,阐述这类代码的几个特征。

特征1:代码简短

“明显没有xx”意味着一眼能看出来,而“一眼”这个条件就有很大的限制。如果给我一个函数,包含1000多行代码,我鼠标滚轮要滚好久,才能过完一遍代码,那么这种代码一定不是“明显没有bug的代码”。那么,反过来说,“明显没有bug的代码”一定是短小的代码。比如,Java中的Objects.equals方法:

public static boolean equals(Object a, Object b) {return (a == b) || (a != null && a.equals(b));
}

这一段代码简短到,代码跟功能定义的文字篇幅差不多,连写文档注释的必要都没有了。还有一个更极端的例子是Java的Objects.isNull方法:

public static boolean isNull(Object obj) {return obj == null;
}

简直就是一段“废话”。

特征2:功能完整且连贯

“一眼能看出”还意味着功能不能太分散,如果一个功能,分散在十多个函数或文件中,那么看这段功能就得在很多代码片段中跳来跳去,这个就需要开发者来阅读代码时充当一个“人肉解释器”的角色,在大脑中把各个代码片段组合起来才能明白整个流程和细节,这无疑降低阅读代码的效率,bug也容易隐藏在各个代码片段的“缝隙”中。举个常见的例子:在图形界面应用中,用户登录后,弹出登录成功的提示,然后关闭登录页面。一种普通的实现是:

//1. 在登录按钮触发登录操作
loginButton.setOnClickListener(v -> controller.login(username, poassword))//2. 在登录成功的回调中展示弹窗
public void onLoginSuccess(User user){LoginSuccessDialog.show("login success")
}//3. 在失败的回调中展示错误信息
public void onLoginFailed(String errorMsg){MessageDialog.showMessage(errorMsg);
}//4. 在LoginSuccessDialog确认后关闭页面
public void onLoginDialogConfirmed(){loginPage.close();
}

看上去好像解耦很不错,但功能都变得七零八落。要拼凑出完整的功能大概得仔细阅读整段代码,更别提“一眼看出”了。那么一眼能看出的代码大概长啥样呢?我想,大概是这样:

loginButton.setOnClickListener(v -> {controller.login(username, poassword).onSuccess(user ->LoginSuccessDialog.总而言之,解耦需谨慎,不要因过度解耦而牺牲了内聚性和连贯性。show("login success").onConfirmed(() -> loginPage.close())).onFailed(errorMsg ->MessageDialog.showMessage(errorMsg));
});

这是对该视图流程的一个连贯的描述,而且篇幅更短。至于获取到用户数据存储到本地数据库、通知其他页面更新等操作,跟当前视图没有关系,也就不需要放在这段代码里。总而言之,解耦需谨慎,不要因过度解耦而牺牲了内聚性和连贯性。

特征3:良好的表达

代码的篇幅得到控制后,要让人一眼看懂,还需要容易理解才行。设计心理学提出“设计传达所有必要的信息,创造一个良好的系统概念模型,引导用户理解系统状态,带来掌控感”。程序设计也是如此,代码是程序功能的文本表达,需要传达对应信息来让人产生该功能正确的概念模型。

以一个常见的上传图片的弹窗为例,思考一个菜单弹窗,包含取消和两个功能按钮:从相册选择和拍照上传,例如下图这样。

那么对应的代码可以表达为:

MenuDialog.create().withAction("拍照上传", dialog -> {takePhoto();}).withAction("本地上传", dialog -> {chooseFromGallery();}).onCancel(() -> {//do something}).show();

或者

MenuDialog.create().withAction("拍照上传", controller::takePhoto).withAction("本地上传", controller::chooseFromGallery).onCancel(() -> {//do something}).show();

没有多余的代码,该有的信息都表达到位,而且和实际功能有良好的对应关系。

4. 特征4:可验证正确性

代码可以让人一眼看懂之后,那么判断其有没有bug,还有一个重要前提:这个代码是有正确性可言的,可以被验证。

例如,来看下面这段随意的代码:

int type;
boolean isClosed;void doSomething(String text) {if (type == 0) {if (isClosed) {println(text);} else {error("something wrong");}} else if (type == 1) {//do something}
}

这段程序简短、易读,但是doSomething函数的行为依赖两个外部变量,而这两个外部变量又容易被其他地方随意改动。比如,type的定义域为1、2、3,但如果type新增类型4的时候或者被错误地赋值为-1的时候,这个doSomething函数的行为还是正确的吗?doSomething函数的正确性依赖于type变量的正确性,那么又依赖于读写type变量的程序的正确性,这样的程序是难以验证的。而且,对上下文依赖越多的程序,越难以产生明确的定义,因为这个定义也依赖上下文的定义。定义不明确,更难以验证内容的正确性。

相比之下,Objects.equalsObjects.isNull方法有着明确的定义,而且不受上下文影响,可以一眼就看出对错。而下面这段代码:

MenuDialog.create().withAction("拍照上传", controller::takePhoto).withAction("本地上传", controller::chooseFromGallery).onCancel(() -> {//do something}).show();

表达明确,可以快速判断出程序行为是否正确、符合期望。即便MenuDialog出现异常,或者takePhotochooseFromGallery出了什么问题,也不需要来修改这段程序。

不过,程序验证是一个有点高深的科研方向,要严格验证一个程序的正确性是很困难的一件事,不过我们仍然可以试着去编写一些“看起来”正确的程序。(利用函数式编程思想写出来的代码通常容易验证一些)

关于“明显没有bug的代码”的一些拙见相关推荐

  1. 请问:如何写出没有BUG的代码?

    全世界只有3.14 % 的人关注了 数据与算法之美 1947年9月9日,美国海军准将 Grace Hopper 在哈佛学院计算机实验室里使用 Mark II 和 Mark III 计算机进行研究工作. ...

  2. 怎样写出没有bug的代码?

    1947年9月9日,美国海军准将Grace Hopper在哈佛学院计算机实验室里使用 Mark II 和 Mark III 计算机进行研究工作.她的团队跟踪到 Mark II 上的一个错误,操作人员发 ...

  3. Windows 蓝屏代码大全,Bug检查代码参考

    浏览器中 ctrl+F 调出查找 属于相应代码即可 下表提供了 Bug 检查代码的链接. 代码 名称 0x00000001 APC_INDEX_MISMATCH 0x00000002 DEVICE_Q ...

  4. 【橙子】C#Winform--贪吃蛇是个人就看的懂的完整无bug逻辑代码

    C#Winform全原创贪吃蛇无bug极致简易小白必学逻辑完整代码 作者写给小白的话: 百度其实有很多贪吃蛇代码,但要么代码过于复杂根本看不懂,要么bug一堆为乞丐版贪吃蛇,要么解释不清楚为残缺代码, ...

  5. [Bug]由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值的解决方法(转)...

    原因 如果使用 Response.End.Response.Redirect 或 Server.Transfer 方法,将出现 ThreadAbortException 异常.您可以使用 try-ca ...

  6. php ip2long bug,PHP代码ip2long 循环有关问题

    PHP代码ip2long 循环问题 print_r($dataIp); foreach ($dataIp as $key=>$value) { $data['ip']     =   $valu ...

  7. 不再重复造轮子,AI 给你推荐更好的代码,还没bug

    2020-09-18 14:47 导语:还在抠bug抠到怀疑人生? 作者 | 青 暮 编辑 | 丛 末 程序员的的代码大部分都不是如同写书法那般一挥而就,而需要反复地抠bug,抠到怀疑人生. 剑桥大学 ...

  8. 程序员写了段代码,自称完美! 网友: 我现在还在改你的Bug

    现在的互联网技术在飞速进步着,加之有一些程序员确实是喜欢编程,长久如此,很多程序员的技术也得到了一个质的飞跃,于是都想写出一个堪称没有Bug的代码! 这不,近日又有一位程序员发帖称: 可以看到,这是一 ...

  9. [转载]基于TFS实践敏捷-修复Bug和执行代码评审

    本主题阐释了这些功能,以继续这一关注虚拟敏捷团队成员的一天的教程. Peter 忙于编写一些代码以完成积压工作 (backlog) 项任务.但是,他的同事发现了一个阻碍他们工作的 Bug,他想立即修复 ...

  10. Patrick Wyatt:代码没问题 程序却有bug?

    摘要:相信每个程序员都遇到过"不可能的bug",代码没有任何问题却出错了!问题肯定是出在操作系统上,或者是工具,甚至是因为计算机硬件的问题?!?当然,魔兽之父也不例外,他在本文中分 ...

最新文章

  1. 人工智能和物联网:智慧城市的交通管理
  2. 【The final】软件工程实践总结
  3. linux安装mysql8.0.18_Linux安装MySQL8.0
  4. java页面可配置化_web.xml页面配置
  5. Java GC系列(4):垃圾回收监视和分析
  6. android 菜单隐藏了,隐藏一些导航菜单菜单项 – Android
  7. poj 1459-Power Network解题报告
  8. 9.1.4 前端 - HTML body标签 - 标题,段落,分割线,换行,特殊符号,列表,超链接,图片,div/span,表格,表单,input标签,多行文本,单选/多选,下拉,按钮...
  9. maven jersey mysql_Maven和Jersey Framework开发REST风格Web Service
  10. SketchUp2019下载SU2019下载安装教程SketchUp草图大师2019下载安装详细教程
  11. 日本python程序员工资_年轻程序员赴日本工作有前途吗?
  12. 服务端使用GZIP压缩数据
  13. Java————错误:找不到或无法加载主类
  14. 【IDE】AndroidStudio关闭Related problems提示
  15. Zigbee HA 框架学习笔记
  16. 解决win10系统CPU占用过高【亲测非常有效】
  17. mars3d与echart图表结合使用
  18. 找工作面试_求职面试和获得Web开发工作的提示
  19. MySQL 连接驱动器包 下载教程
  20. 学习记录-视觉SLAM十四讲第2版(二)

热门文章

  1. iKuai软路由模拟环境搭建
  2. SD-WAN,一场广域网的革命
  3. 国内能使用的海外支付接口除了Stripe,Paypal还有哪些?
  4. el-form 表单的校验
  5. 【原创】我所认识的银行业务之旅(开篇)
  6. STM32F103RCT6使用HY-SRF05 五针超声波测距模块进行测距实现
  7. 计算机找不到海信电视,海信电视突然看不了电视直播了,怎么解决?当贝市场良心分享...
  8. 红米手机html文件,红米手机中ES文件浏览器无法删除SD卡中文件的解决办法-es文件浏览器...
  9. Thesus(忒修斯)的故事
  10. 马云、张小龙、雷军缅怀金庸:江湖路远,侠义长存!