<meta content="text/html; charset=utf-8" http-equiv="CONTENT-TYPE"><meta name="GENERATOR" content="OpenOffice.org 2.2 (Linux)"><meta name="AUTHOR" content="Jeff Xiong"><meta name="CREATED" content="20070411;18435000"><meta name="CHANGEDBY" content="Jeff Xiong"><meta name="CHANGED" content="20070411;22330000"> <style type="text/css"> </style>
多年以前,我曾经参与过一个政府项目的开发。一天傍晚,我和另一位同事正在这个政府机关的机房里做例行检查。一切看起来都运行正常,我们打算做完检查就下班回家。这时客户走了进来。
“网站上有一个数据显示得不太好看,你们能不能调一调?”他问我们。
看起来不是一件难事,那又何必要拖到明天呢?我们打开笔记本电脑,调出源代码。不过是改变一个数据的显示,三下五除二弄好了就部署上去,客户一定很开心,我们这样想着。但很快我们就发现事情没有那么简单:客户需要的数据实际上涉及到后台的一系列计算,而我们现有的领域对象并不能很容易地完成这样的计算。幸运的是,我这位同事素有“快手”美誉,写起代码来真是不含糊。几分钟功夫,他就修改了以前的领域对象,算出了客户想要的数据。
编译,打包,发布——倒霉。网站上出现了好几处古怪的数据,即使不运行QA测试脚本我也能看出,一定有什么东西被我们弄坏了。“没问题,”这位同事自信地说,“分分钟搞定。”只见他鼠标如飞,在Eclipse里打上几个断点,紧跟着就进入了调试视图。一行行代码被高亮显示,一串串上下文信息出现在检视窗口上。他的脸上露出胸有成竹的表情,那是高手宣告“一切尽在掌握”的表情。一个小问题,几分钟就可以搞定,只不过再一次展现高手的功力而已,不是吗?
三十分钟过去了,他的表情变得紧张。修改过的代码越来越多,而出现的问题似乎在随着代码的修改量成正比上升。“真的没问题吗?”身为初哥的我怯怯地问道。“放心。”简练有力的回答,然后是……又一个三十分钟。他的额头开始渗出密密的汗珠,而我已经跟不上他的思维了——我甚至怀疑他是否还清楚自己的思维,因为他在调试器中的操作越来越频繁地出错。噢,天啊,我们怎么会落到这步田地?
最终客户拯救了我们——虽然当他走进机房、诧异地说“你们怎么还没弄好”时我尴尬得无地自容,但当他说出“明天再来弄吧”我还是长舒了一口气。说来也怪,第二天我们轻轻松松就把这个修改完成了,前后真的只用了十分钟。谁知道呢,人都有赶上这寸劲的时候。
也许是这一次的经历让我印象太过深刻,从那以后,我一看见调试器就有点手发抖心发怵。这时读者要问了:你身为程序员有这种心理障碍,不就好像大厨握不住菜刀、侠客抓不紧宝剑么?你还怎么能吃这碗饭呢?原因是,自从那一次刻骨铭心的经历之后,我就一直坚持着……
测试驱动开发
这是个酷词,换成它的英文缩写(TDD)就更显得酷,所以人们都喜欢把它挂在嘴边,还喜欢把它说得倍儿复杂、倍儿深奥。其实在我看来,测试驱动开发这件事非常简单,总共就3步:
-
红:动手做任何一件事之前,先写一个测试来描述你将要做的事情;既然你还没有做这件事,所以测试无法通过,测试状态为红色。
-
绿:写尽可能简单的代码,让测试通过,状态条变成绿色。
-
扫扫地:刚才写的代码够不够漂亮?看着不爽的话就把它整理一下(更酷的说法叫“重构”),整理完之后测试状态应该仍然是绿色。
(有人跳起来喊了:难道这就是你的工作方式吗?别说没有做设计了,连实现都是“尽可能简单的”。你要怎么保证以后的可扩展性呢?
对于这个问题的标准答案是:以后的事以后再说。任何更高级更复杂的设计,你都有可能不需要它。用客户花钱的时间来做一个可能不需要的功能或者设计,说得重了就是缺乏职业道德。可不要忽视了简单的力量:越简单的代码越不会出错,越简单的代码越容易扩展。)
“一红,一绿,扫扫地”。这几年的程序人生,我就念着这句口诀,一小步一小步走了过来。奇妙得很,这一路上,还真是没怎么开过调试器。要知道个中缘由,得从一种传染性的心理疾病说起……
Test Infected
这是Erich Gamma大师发明的词,照我理解就是不问三七二十一,每天嘴里不停念叨着“一红,一绿,扫扫地”……的强迫症早期症状(例如像我这样^_^)。据我所知,很多人像我一样,主动选择患上“测试驱动强迫症”(很酷的缩写叫TDO),就是为了逃避“调试器焦虑综合症”(也有一个很酷的缩写叫DAS)。一项非官方调查数据显示,程序员每次打开调试器所需的时间平均是4分钟——“这不可能!”有人喊道,“我的调试器只要1秒钟就能跳出来。”没错,但你需要时间来设置断点、执行程序、找到适当的运行上下文、检视需要的变量……更要命的是,中间一个误操作就会让你这次调试付诸东流。所有这些让调试器成了一个相当耗费时间的工具。
(另一项调查数据显示,在没有实施TDD的情况下,程序员每小时平均打开调试器8次。啊哈……)
于是问题来了:我们为什么需要调试器?因为我们要知道程序运行中的状态。很好。然后下一个问题是:我们为什么要知道程序运行中的状态?呃……因为程序模块内部太复杂,以至于我们无法一目了然地看懂,不是吗?因为程序模块之间有太多的耦合,以至于一处修改很容易引发各处无法预知的变动,不是吗?承认吧,烂代码是需要调试的第一原因,并且我们都会写出烂代码。
而“测试驱动强迫症”的一大好处是它让你更难写出烂代码——因为你首先就很难给过于复杂、或者与别的模块有太多耦合的程序模块编写测试。还记得IoC模式吗?(对那些错过三年前的Spring热潮的读者说抱歉^_^)对于TDO患者而言这个模式——至少在使用Java时——简直是顺理成章、不言自明的,否则你怎么能把一堆纠结不清的对象摘得干干净净分别测试呢?至于复杂得难以一眼看清的方法,TDO患者们更是想都不会想要写出这种东西来,因为那意味着他们必须首先写出一个同样复杂(甚至更加复杂)的测试。谁会跟自己过不去呢?
直接的结果是,作为一种强迫症,TDO强迫你写出短小易懂、功能内聚、耦合松散的代码,并把你从DAS的痛苦解救出来。并且很多TDO患者曾经是DAS患者这一事实有效地促进了TDO对于代码质量的提升作用:这些人在遇到复杂的情况时,会优先选择把现有代码重构得清晰易懂,以尽量避免打开调试器。
TDO症状分析
(以下是对TDO患者病情的一些分析,我希望读者能理解一个强迫症患者的苦衷……)
复杂的操作——例如与外部系统之间的I/O——是人们打开调试器的一个理由,但这些操作恰恰是需要并且应该被良好封装起来的。如果不能有效地用mock对象或者测试沙箱来编写测试,你可能面临一个比DAS更严重的问题:你的系统很可能正在与当前使用的操作系统、甚至当前使用的这台机器紧密耦合。TDO强迫你在自己的系统和外部系统之间划清界限,这对于未来的部署和移植都有很大的帮助。
更复杂的操作——例如多线程和事务——是打开调试器的更强烈的理由。但有趣的是,这些操作往往很难调试(如果不是根本无法调试的话)。反倒是通过精心编写测试,你可以控制程序以你希望的方式精确运行,从而有效地诊断和解决问题——并保证同样的问题不再出现,因为测试会不断被运行。
很多编程语言——例如JavaScript、Ruby和PHP——不像Java那么容易调试。就拿JavaScript来说,要调试它需要用到Firebug之类华丽的工具。(顺便说一句,我愿意出10块钱跟任何人赌他不喜欢用Firebug来调试。)在这种情况下,你通常会倾向于把每个模块的复杂度都控制在可以用一条输出语句看清其内部状态的程度,并依靠测试来单独诊断每个模块。
TDO患者还倾向于让测试在失败时输出尽可能有意义的信息,例如“expected: 100, actual: 99”就比“false is not true”要好。(读者可以试着研究一下你的测试框架,看它在什么情况下会输出这两种失败信息,这有助于你了解TDO患者的心理状态。)
频繁运行所有测试是TDO患者的症状之一:如果不能每过15分钟就把所有测试都运行一遍并看到绿条,他们就会表现出轻度躁狂症状。出于对自己脆弱心理的保护,他们会小心地避免在测试中执行网络操作或数据库操作,其副作用是把对外部系统的依赖有效地封装起来,从而有效地减少需要打开调试器的机会。
当然在确实有必要的时候(这种情况极其罕见),TDO患者还是会打开调试器。不过正如前面说过的,很多TDO患者曾经是DAS患者,所以他们会让自己在DAS发作之前离开调试器,并通过编写更多的测试、做更多的重构来避免再次打开调试器。在DAS无可避免地即将发作之前——这大概是进入调试器5分钟之后——他们会撤销刚才所做的一切修改,从前一个绿条的状态开始重新做这一次的任务。
所有人都知道,如果没有麻烦,我们是不会打开调试器的。不过在一个TDO患者看来,如果打开调试器,那就意味着你真的有麻烦了。即便你——暂时地——还不是DAS患者,也许你也应该记住这个忠告。
分享到:
相关推荐
本文将深入探讨MCD2--ICD2仿真调试器及其USB驱动程序,帮助用户理解其功能、作用以及如何正确安装和使用。 MCD2--ICD2(Microcontroller Debugger -- In-Circuit Debugger 2)是一种专门用于微控制器(MCU)开发和...
ServoStudio是高创公司为CDHD系列伺服驱动器设计的一款专业级调试工具,它集参数设置、故障诊断、性能测试等多种功能于一体,使得用户可以对驱动器进行深度调整,以适应各种复杂的工业应用需求。 1. 参数设置:...
5. **设置调试器**:在Visual Studio的调试器选项中,配置内核模式调试,连接到目标计算机(本地或远程),以便运行并调试驱动。 6. **启动调试**:点击“调试”>“开始调试”,VisualDDK将自动加载WinDbg,并在...
GoodDbg破解版 GoodDbg调试器 VT调试器 过所有驱动保护
本集合提供了一系列的工具,帮助开发者高效地进行驱动程序的开发、测试和调试。下面将详细介绍这些工具的功能和用途。 1. **USBlyzerSetup.exe**:USBlyzer是一款强大的USB协议分析工具,它能捕获并解析USB设备的...
3. **调试流程**:使用UP-Debugger时,开发者首先需要安装相应的驱动程序,确保电脑能够识别并连接到调试器。然后,通过调试工具设置目标设备的连接参数,加载待调试的固件或应用程序。在调试过程中,可以设置断点,...
SSCOM是一款串口通信调试工具,可以帮助用户测试和调试串口通信设备。它支持多种串口通信协议,包括RS232、RS485和MODBUS等。使用SSCOM,用户可以通过串口连接计算机和目标设备,发送和接收数据,并进行调试和测试。...
以色列Elmo驱动器调试软件,电机参数配置,性能参数调试,内置示波器 以色列Elmo驱动器调试软件,电机参数配置,性能参数调试,内置示波器
QTP脚本调试器是QTP中的一个重要组件,它允许用户在执行自动化测试脚本时进行单步调试,查找并解决可能出现的问题。下面将详细介绍QTP脚本调试器的使用及其相关知识点。 1. **脚本编辑器**: QTP的脚本编辑器是...
信捷伺服驱动器调试软件ThingetServo是一款专为信捷品牌伺服驱动器设计的专业工具,主要用于伺服驱动器的参数设置、故障诊断以及性能测试。该软件的版本为V1.2.0.2,体现了其在不断更新优化中,以满足用户对更高效、...
### 音圈电机驱动器PAC483调试手册知识点概览 #### 一、安装RS485通信线驱动程序 - **目的**: 实现计算机与音圈电机驱动器之间的通信。 - **方法**: 如果使用的是USB转RS485通信线,则需先安装USB驱动程序。 - ...
3. 调试开始:一旦驱动被加载,开发者可以使用内置的调试工具(如WinDbg)或者集成开发环境中的调试器来跟踪驱动的运行情况。这包括设置断点、查看变量值、检查内存状态等。 4. 错误检测与修复:通过观察调试信息,...
Kollmorgen AKD驱动器高级调试手册是一份专注于AKD系列伺服驱动器高级调试的文档,该文档详尽阐述了伺服调试的原理、方法及如何手动调整系统参数来优化伺服电机控制。手册中不仅涵盖了AKD驱动器的工作原理和操作模式...
V0702WIN.exe是Fagor公司推出的一款专门用于调试和配置伺服驱动器的软件工具,适用于Windows操作系统,它提供了全面的功能,包括参数设置、故障诊断、性能测试等。 二、Fagor伺服驱动调试软件V0702WIN.exe的使用 1...
**libusb 万能驱动调试工具详解** libusb 是一个开源的库,它提供了一种跨平台的方式来访问USB设备。这个“libusb 万能驱动调试工具”是基于libusb库开发的应用程序,专为USB设备的调试和交互设计。在进行USB设备的...
《DLT645-2007多功能电能表通信协议调试器》是一个专门针对电能表通信协议进行测试和调试的专业工具。在电力系统自动化领域,这种调试器扮演着至关重要的角色,确保电能计量设备与系统之间的数据交换准确无误。下面...
《H5小游戏源码:手机强迫症测试》 在当今数字化时代,H5技术因其跨平台、易分享的特性,成为开发小游戏的热门选择。"手机强迫症测试"这款H5小游戏,以其独特的主题和互动体验,吸引着众多用户参与。下面我们将详细...
如果操作系统找不到驱动,可能需要在设备管理器中手动添加驱动。 “51调试助手”则是一个软件工具,用于辅助开发人员进行51单片机的程序调试。它通常包含诸如设置断点、查看变量值、单步执行等功能,有助于找出代码...
在Windows操作系统环境中,驱动加载工具是开发者用于测试和调试设备驱动程序的重要辅助工具。它简化了将自定义或编写的驱动文件安装到系统的过程,使得内核级别的开发和调试更为高效。本文将深入探讨驱动加载工具的...
驱动调试在IT行业中是一项至关重要的任务,特别是在开发和优化硬件设备与操作系统交互的软件时。在Windows系统中,驱动程序是连接硬件设备和操作系统的核心组件,它们负责解释来自操作系统的指令,并控制硬件设备...