敏捷的调试

敏捷调试

记录解决问题的日志

面对问题并解决它们所开发人员的一种生活方式。当问题发生时,咱们但愿赶忙把它解决掉。若是一个熟悉的问题再次发生,咱们会但愿记起第一次时如何解决的,并且但愿下次可以更快地把它搞定。然而,有时一个问题看起来跟之前遇到的彻底同样,可是咱们却不记得说如何修复的了。这种情况时常发生。编程

从网上寻找答案固然赛过仅靠我的努力解决问题,可这是很是耗费时间的过程。有时能够找到须要的答案,有时出了找到一大堆意见和建议以外,发现不了实质性的解决方案。安全

Don't get burned twice
要想获得更好的效果,不妨维护一个保存曾遇到的问题以及对应解决方案的日志,能够快速搜索之前用过的方法,它叫每日日志(daylog)服务器

能够选择符合需求的任何格式。好比,网络

  • 问题发生日期
  • 问题简述
  • 解决方案详细描述
  • 引用文章或网址,以提供更多细节或相关信息。
  • 任何代码片断、设置或对话框的截屏,只要它们说解决方案的一部分,或者能够帮助更深刻地理解相关细节。框架

  • 要把日志保存为可供计算机搜索的格式,就能够进行关键字搜索以快速查找细节。
  • 若是面临的问题没法在日志中找到解决方案,在问题解决以后,要记得立刻将新的细节记录到日志中去。
  • 要共享日志给他人,而不只仅是靠一我的维护。把它放到共享的网络驱动器中,这样其余人也可使用。或者建立一个wiki,并鼓励其余开发人员使用和更新其内容。工具

具体技巧

  • 记录问题的时间不能超过解决问题上花费的时间。要保持轻量级和简单,没必要达到对外发布时的质量。
  • 找到之前的解决方法很是关键,使用足够的关键字,能够帮助你在须要的时候发现须要的条目。
  • 若是经过搜索Web,发现没人曾经遇到一样的问题,也许搜索的方式有问题。
  • 要记录发生问题时应用程序、应用框架或平台的特定版本。一样的问题在不一样的平台或版本上可能表现得不一样。
  • 要记录团队作出一个重要决策的缘由。不然,在6~9个月以后,想再从新回顾决策过程的时候,这些细节就很难再记得了,很容易发生互相指责的情形。

警告就是错误

当程序中出现一个编译错误时,编译器或是构建工具会拒绝产生可执行文件。咱们别无选择——必需要先修正错误,再继续前行。单元测试

然而警告倒是另一种情况。即便代码编译时产生了警告,咱们仍是能够运行程序。有些警告说过于挑剔的编译器的良性副产品,有些则不是。测试

可能有人会说优秀的单元测试能够发现这些问题。说的,可若是编译器能够发现这种问题,那为何不利用它呢?者能够节省大量的时间和麻烦。要找到一种方式让编译器将警告做为错误提示出来。若是编译器容许调整警告的报告级别,那就把级别调到最高,让任何警告不能被忽略。设计

在修改设置的时候,要记得在构建服务器上使用的持续集成工具中,修改一样的设置选项。这个小小的设置,能够大大提高团队签入到源码控制系统中的代码质量。调试

具体技巧

  • 虽然这里探讨的主要是编译语言,解释型语言一般也有标志,容许运行时警告。使用相关标志,而后捕获输出,以识别并最终消除警告。
  • 因为编译器的bug或是第三方工具或代码的缘由,有些警告没法消除。若是确实没有应对之策的话,就不要再浪费更多时间了。可是相似的情况不多发生。
  • 应该常常指示编译器:要特别注意别将没法避免的警告做为错误进行提示,这样就不用费力去查看全部的提示,以找到真正的错误和警告。
  • 弃用的方法被弃用是有缘由的。不要再使用它们了。至少,安排一个迭代来将它们以及它们引发的警告信息安全地移除掉。
  • 若是将过去开发完成的方法标记为弃用方法,要记录当前用户应该采起何种变通之策,以及被弃用的方法将会在什么时候一块儿移除。

对问题各个击破

单元测试带来的积极效应之一,是它会强迫造成代码的分层。要保证代码可测你,就必须把它从周边代码中解脱出来。若是代码依赖其余模块,就应该使用mock对象,来把它从其余模块中分离开。这样作不但让代码更加健壮,且在发生问题时,也更容易定位来源。

不然发生问题时有可能无从下手。也许能够先使用调试器,逐行执行代码,并试图隔离问题。也许在进入到感兴趣的部分以前,要运行多个表单或对话框,这会致使更难发现问题的根源。你会发现本身陷入整个系统之中,徒然增长了压力,并且下降了工做效率。

大型系统很是复杂——在执行过程当中会有不少因素起做用。从整个系统的角度来解决问题,就很难区分开,哪些细节对要定位的特定问题产生影响,而哪些细节没有。

答案很清晰:不要试图立刻了解系统的全部细节。要想认真调试,就必须将有问题的组件或模块与其余代码库分离开来。若是有单元测试,这个目的就已经达到了。不然,你就得开动脑筋了。

Prototype to isolate.
识别复杂问题的第一步,是将它们分离出来。

但是,不少应用的代码在编写时没有注意到这一点,使得分离变得特别困难。应用到各个构成部分之间会彼此纠结:想把这个部分单独拿出来,其余的会紧随而至。在这些情况下,最好花一些时间把关注的代码提取出来,并且建立一个可让其工做的测试环境。

隔离问题不该该只在交付软件以后才着手。在构建系统原型、调试和测试时,各个击破的战略均可以起到帮助做用。

具体技巧

  • 若是将代码从其运行环境中分离后,问题消失不见了,这有助于隔离问题。
  • 另外一方面,若是将代码从其运行环境中分离后,问题还在,这也有助于隔离问题。
  • 以二分查找的方式来定位问题时颇有用的。
  • 在向问题发起攻击以前,先查找你的问题解决日志。

报告全部异常

从事任何编程工做,都要考虑事物正常情况下是如何运做的。不过更应该想想,当出现问题——也就是事情没有按计划进行时,会发生什么。

在调用别人的代码时,它也许会抛异常,这时咱们能够试着对其处理,并从失败中恢复。固然,要是在用户没有意识到的状况下,能够恢复并继续正常处理流程最好不过了。要是不能恢复,应该让调用代码的用户知道,究竟是哪里出现了问题。

具体技巧

  • 决定由谁来负责处理异常是设计工做的一部分。
  • 不是全部的问题都应该抛出异常。
  • 报告的异常应该在代码的上下文中有实际意义。
  • 若是代码中会记录运行时调试日志,当捕获或是抛出异常时,都要记录日志信息;这样作对之后的跟踪工做颇有帮助。
  • 检查异常处理起来很麻烦。没人愿意调用抛出31种不一样检查异常的方法。这是设计上的问题:要把它解决掉,而不是随便打个补丁就算了。
  • 要传播不能处理的异常。

提供有用的错误信息

当应用发布而且在真实世界中获得使用以后,仍然会发生这样那样的问题。当没法知足用户需求时,要以优雅的方式进行处理。相似的错误发生时,是否是只要弹出一条优雅且带有歉意的信息给用户就足够了?并不尽然。固然了,显示通用的信息,告诉用户发生了问题要好过因为系统崩溃形成应用执行错误的动做,或者直接关闭(用户会所以感到困惑,并但愿知道问题所在)。然而,相似“出错了”这样的消息,没法帮助团队针对问题作出诊断。用户在给支持团队打电话报告问题时,咱们但愿他们提供足够多且好的信息,以帮助尽快识别问题所在。遗憾的是,用很通用的错误消息,是没法提供足够的数据的。

针对这个问题,经常使用的解决方案是记录日志:当发生问题时,让应用详细记录错误的相关数据。错误日志最起码应该以文本文件的形式维护。不过也许能够发布到一个系统级别的事件日志中。可使用工具来浏览日志,产生全部日志信息的RSS Feed,以及诸如此类的辅助方式。

记录日志颇有用,但是单单这样作是不够的。开发人员认真分析日志,能够获得须要的数据,但对于不幸的用户来讲起不到任何帮助做用,他们仍是一点头绪都没有,不知道本身到底作错了什么,应该怎么作能够绕过这个错误,或者在给技术支持打电话时应该报告什么。

若是你注意的话,在开发阶段就能发现这个问题的早期警告。做为开发人员,常常要将本身假定为用户来测试新功能,要是错误信息很难理解或者无助于定位错误的话,就能够想一想真正的用户和支持团队,遇到这个问题时会有多么困难了。

一方面要提供给用户清晰、易于理解的问题描述和解释,使他们有可能寻求变通之法。另外一方面还要提供具有关于错误的详细技术细节给用户,方便开发人员寻找代码中真正的问题所在。

错误报告对于开发人员的生产率,以及最终的支持活动消耗成本,都有很大的影响。在开发过程当中,若是定位和修复问题让人倍受挫折,就考虑使用更加积极主动的错误报告方式吧,调试信息很是宝贵,并且不易得到。不要轻易将其丢弃。

具体技巧

  • 像“没法找到文件”这样的错误信息,就其自己而言无助于问题的解决。“没法打开...以供读取”这样的信息更有效。
  • 没有必要等待抛出异常来发现问题。在代码关键点使用断言以保证一切正常。当断言失败时,要提供与异常报告一样详细的信息。
  • 在提供更多信息的同时,不要泄露安全信息、我的隐私、商业机密或其余敏感信息。
  • 提供给用户的信息能够包含一个主键,以便于在日志文件或是审核记录中定位相关内容。
相关文章
相关标签/搜索