异常驱动的开发(Exception-Driven Development)
你的网站或应用程序存在哪些问题?如果你在等着用户来告诉你,那么你只能看到所有的问题中已经暴露的那极小的一部分。要知道,那只是“冰山一角”!
而且,如果你真的是在守株待兔,我不得不很抱歉地告诉你,你有点失职——你应该比用户更了解你的程序的健康状况。每当有用户告诉我一个他们在使用我的软件的过程中碰到的“善意的错误”时,我总会感到局促不安。甚至有些惭愧。我没有在用户把问题告诉我之前发现它们,并且事先解决它们,这就是我的失职。我忽视了对程序崩溃应付的责任。
任何负责任的软件项目,首先要做的事是建立一种异常和错误报告机制。Ned Batchelder把这比作为“先给自己戴好氧气罩,然后再帮小朋友戴”:
当你的程序出现问题时,请你总是先去检查这个错误是否被适当处理了。如果没有被适当处理,那么先去解决错误处理代码里的问题。保持这个工作顺序很重要,原因有如下几方面:
- 在根源错误还在的情况下,你实际上为错误处理代码中的bug准备了一个完美的测试用例。但如果你先把根源问题解决了,你又将怎样来测试你的错误处理代码呢?记住,你的代码里之所以有bug,部分原因就是它在当初的开发阶段很难被测到。
- 一旦根源问题被解决了,解决错误处理代码里的问题的紧迫性便随之消失。你可能会说,“我以后会去解决的,现在急啥?”就好比你家屋顶漏了——下雨的时候,你没办法去修屋顶,因为外面正下着雨呢;但雨停了之后,家里又不漏水了(不急着去修屋顶了)!
你需要集中在一个地方去处理所有的错误。这个地方是你团队里的所有开发人员非常熟悉的,并且每天都会接触到。在Stack Overflow,我们采用了ELMAH(https://code.google.com/p/elmah)的一个自定义分支。
我们每天都在监视着这些异常日志;有时候每个小时都察看。这些异常日志实际上已经成为了我们团队的To-Do列表(待办事项)。我们这么做是有充分理由的。比如,微软收集类似的这种错误日志已经几年了,他们不仅收集自家软件的日志,还收集第三方软件的;他们的这个机制叫Windows Error Reporting(简称WER)。成效喜人啊:
当最终用户遇到程序崩溃时,他们会看到一个对话框,问他们是否想发送错误报告。如果他们选择发送,WER会收集应用程序以及发生崩溃的模块的信息,然后把这些信息通过一个安全服务器发送给微软。
于是,软件厂商可以访问到关于他们产品的数据,再加以分析,定位到问题的根源。他们可以通过错误对话框与用户交互,还可以通过Windows Update升级他们的程序。
在对错误报告数据的广泛分析之后,我们看到:80%的客服问题在修复了用户报得最多的20%的bug之后就能得到解决。即使只修复用户报得最多的1%的bug,也能解决50%的客服问题。这个分析结果通常对于各家公司都是成立的。
尽管我仍然推崇“测试驱动开发”(Test-Driven Development,缩写为TDD),但时间投入的投机性一直是我纠结的一个问题。如果你修复了一个真实用户永远也碰不到的bug,那你的修复有什么价值呢?我知道还有很多其他的理由促使我们去实践TDD,但若单纯作为一种修复bug的机制,在我看来,选用TDD就大可不必了;就像我们过早地进行代码优化一样,是不可取的。我更愿意把时间花在解决真实发生的问题上,而不是那些理论上存在的bug。
当然,你可以两者都做。但考虑到开发时间总是有限的,我更倾向于立足于实实在在的数据,把时间花在解决真实用户在使用我的软件过程中碰到的问题上。这就是我所谓的“异常驱动的开发”(Exception-Driven Development)——将你的软件发布出去,让尽可能多的用户使用它,然后一心一意地研究他们产生的错误日志。使用那些异常日志去找出问题的根源,并且专注在你的代码中有问题的区域。重新架构,重构代码,以消除最严重的3个问题。快速迭代,部署,如此周而复始。这种数据驱动的反馈机制是非常有效的,几个迭代下来,你的程序将非常稳定,坚如磐石。
异常日志可能是用户能够提供给你的最强有力形式的反馈。这种反馈基于已经发布的软件,为了得到它们,你不必去询问用户或者诱导他们,也不必理会他们关于问题的不可思议、似是而非的描述。真正的问题伴随着转储出来的堆栈跟踪信息,已经悄悄地为你自动收集好了。异常日志才是用户反馈中的根本。
(译者注:2009年4月16日,DareObasanjo与Scott Koon @lazycoder在Twitter上有过一次辩论;Dare Obasanjo的观点是:通过将产品发布出去,然后从客户那里得到真实的反馈,这比任何事先的沟通或调研更有价值。)
我是在提倡发布带有bug的代码吗?或者半成品?或者狗屎软件?当然不是!我的意思是说,你越快将你的软件推到真实用户的面前,你就会得到越多的数据以改进你的软件。异常日志在这个过程中扮演着很重要的角色,同样地,用户使用数据也很重要。当然,如果你受得了的话,你还应该跟用户交谈。
不管怎么样,软件在发布的时候总是会带有bug的。所有软件都是这样。只要是软件,它就会崩溃,它就可能丢失数据,它还会难以学习、难以使用。问题不在于你在发布软件的时候带出去了多少bug,而在于你能多快地修复那些bug?如果你的团队一直在践行异常驱动的开发模式,答案就很简单了——别担心,我们马上就会改进我们的软件!看着吧,我们会越做越好!
听起来多美妙啊!就像一首美妙的乐曲,在每个用户的耳边萦绕……
异常驱动的开发(Exception-Driven Development)的更多相关文章
- 【翻译稿】Behavior Driven Development (BDD)行为驱动开发
这是一篇翻译稿,方便给不知道BDD的同学扫盲.原文链接:What is BDD (Behavior Driven Development)? | Agile Alliance Definition定义 ...
- Bug驱动开发(Bug-driven development)
说实话,作为一个Domino开发者,像測试驱动开发(Test-driven development).功能驱动开发(Feature-driven development)之类软件开发的高大上的方法论( ...
- 敏捷软件开发 Agile software Development(转)
原文链接: http://www.cnblogs.com/kkun/archive/2011/07/06/2099253.html 敏捷软件开发 Agile software Development ...
- 编写高质量代码改善C#程序的157个建议[用抛异常替代返回错误、不要在不恰当的场合下引发异常、重新引发异常时使用inner Exception]
前言 自从.NET出现后,关于CLR异常机制的讨论就几乎从未停止过.迄今为止,CLR异常机制让人关注最多的一点就是“效率”问题.其实,这里存在认识上的误区,因为正常控制流程下的代码运行并不会出现问题, ...
- Java异常:选择Checked Exception还是Unchecked Exception?
http://blog.csdn.net/kingzone_2008/article/details/8535287 Java包含两种异常:checked异常和unchecked异常.C#只有unch ...
- S3C2440触摸屏驱动实例开发讲解
出处:http://www.embeddedlinux.org.cn/html/yingjianqudong/ 一.开发环境 主 机:VMWare--Fedora 9 开发板:Mini2440--6 ...
- Vs2010 配置驱动的开发环境
我已被用来VS2010开发环境,之前曾经与vs2010驱动的开发环境.重装系统,一次又一次的配置,找了好几篇文章,配置没有成功,在配置阶段突然成功了,直接把原来的驱动程序的配置文件将能够接管使用. 当 ...
- hibernate异常:org.hibernate.exception.GenericJDBCException
异常:org.hibernate.exception.GenericJDBCException 提示:Cannot open connection 提示:不能打开链接 一般这个异常是由 java.sq ...
- Atititjs javascript异常处理机制与java异常的转换.js exception process
Atititjs javascript异常处理机制与java异常的转换.js exception process 1. javascript异常处理机制 Throw str Not throw err ...
随机推荐
- scratch写的图灵机
大多数人对于scratch不感冒,因为觉得这是孩子玩的.的确,积木的方式不适合专业程序员写代码,然而别小看scratch,怎么说,它也是图灵完备的.而且,过程支持递归,虽然带不了返回值. 虽然计算速度 ...
- 利用Filter和拦截器,将用户信息动态传入Request方法
前言: 在开发当中,经常会验证用户登录状态和获取用户信息.如果每次都手动调用用户信息查询接口,会非常的繁琐,而且代码冗余.为了提高开发效率,因此就有了今天这篇文章. 思路: 用户请求我们的方法会携带一 ...
- MongoDB $type条件操作符
描述 在本章节中,我们将继续讨论MongoDB中条件操作符 $type. $type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果. MongoDB 中可以使用的类型如下表所示: 类型 ...
- Android源码解析——AsyncTask
简介 AsyncTask 在Android API 3引入,是为了使UI线程能被正确和容易地使用.它允许你在后台进行一些操作,并且把结果带到UI线程中,而不用自己去操纵Thread或Handler.它 ...
- Hibernate设置时间戳的默认值和更新时间的自动更新
Generated and default property values 生成的和默认的属性值 The database sometimes generates a property value, ...
- Dubbo框架应用之(三)--Zookeeper注册中心、管理控制台的安装及讲解
我是在linux下使用dubbo-2.3.3以上版本的zookeeper注册中心客户端.Zookeeper是Apache Hadoop的子项目,强度相对较好,建议生产环境使用该注册中心.Dubbo未对 ...
- DB查询分析器7.01新增的周、月SQL执行计划功能
DB查询分析器7.01新增的周.月SQL执行计划功能 马根峰 (广东联合电子服务股份有限公司, 广州 510300) 1 引言 中国本土 ...
- 剑指Offer——常用SQL语句、存储过程和函数
剑指Offer--常用SQL语句.存储过程和函数 常用SQL语句 1.在MySQL数据库建立多对多的数据表关系 2.授权.取消授权 grant.revoke grant select, insert, ...
- Android图表库MPAndroidChart(一)——了解他的本质,方能得心应手
Android图表库MPAndroidChart(一)--了解他的本质,方能得心应手 我们项目中经常会遇到一些统计图,比如折线图,线形图等,在一些运动健康类的App中尤其的常见,这画起来要命,我以前就 ...
- Dynamics CRM2013 Form利用window.location.reload()进行全局刷新带来的问题及解决办法
CRM2013以后,表单的保存后变成了局部刷新而非全局刷新,但很多情况下我们需要刷新整个页面,通过刷新页面来使脚本执行或者业务规则执行来实现某些业务效果,一般我们会使用window.location. ...