在用尽所有途径修复错误后该怎么办


13

我是一名初级程序员(到目前为止有4个月的职业经验)正在跨平台移动应用程序上工作(一个人的团队,所以这只是我自己)。

我在此程序/应用程序中存在一个错误,该错误很大(30个不同的头文件,每个头文件也都有自己的cpp文件)。我一直在试图确切地找到错误的根源并进行修复(甚至尝试使用一些hacks使其正常工作),但是有大约十几种或更多种解决方案(我知道导致问题的原因)我什么都没提出来,导致我无法准确跟踪错误或修复了错误。

您是否对使用一些广泛技术的初级程序员有任何建议(可以运行,将我的所有代码打印到纸上并用笔通过它,等等),我可以用来协助解决此错误吗?

为我的错误提供更多背景信息;它涉及跨平台API Mosync,当我执行特定的操作序列时,当前屏幕不会重绘(并显示)以前显示的屏幕仍在接收指针/按键事件,而不是当前屏幕。

具体顺序:
-显示菜单屏幕-单击“显示上一个订单按钮”
-显示前一个订单屏幕-单击“加载文件”,然后单击菜单按钮并打开交货屏幕
-显示交货屏幕-单击菜单按钮并打开采购屏幕
-显示采购屏幕-此处错误,未显示/未响应此屏幕的输入,ListViews不滚动,按钮不响应点击,ListView单元格不响应点击


我会接受建议,每次执行相同的步骤时,该错误都是100%可重现的,尽管由于我无法理解API的一部分,仍然很难弄清指针事件是如何传输的以及显示在什么屏幕上达到(或不知道如何)。

另外,我也希望在我的工作中拥有另一双眼睛,并指出错误,但是正如我所说的那样,我是一个由1人组成的团队,我的老板指导我,他拥有公司,并且对应用程序有想法,但是不知道c ++或任何最近的语言(cobal?我想是全部)。关于如何在不违反/不炫耀公司知识产权代码/财产的情况下获得第二只眼睛的任何建议?

...而且不离开这个有薪实习是不可行的,合同说如果我在1200万合同的6个月之前离开,我可能有责任支付我年薪的30%


6
它是100%可重现的吗?

5
简单的答案就是让您的同事参与其中。作为一个团队,您将很快解决它。
Fattie

2
@Joe-并非总是如此。例如,多个复杂的交互子系统的集体行为中的错误,其中,由于子系统的模棱两可的模棱两可而导致了不同的子系统在构建时各自的角色具有微妙的不兼容视图,通常很少有人对多个子系统及其交互有详细的了解才能诊断出这些问题。有时,您需要让所有团队进行讨论,当两个人开始互相称呼白痴时,他们就有可能在讨论与不相容的假设相关的一些东西。
Steve314

我合并了您的帐户。您可以使用Yahoo OpenID登录。我也在编辑您的问题,以包括您作为答案发布的信息。
亚当李尔

顺便说一句 除了下面的回答外,我还在Wikipedia上阅读到Mosync是否不再维护?
布拉德·托马斯

Answers:


19

如果您可以100%地重现问题,请在最后一步上(尽可能早)设置一个断点。如果您遍历整个调用堆栈,我很确定您会在某个地方得出一些意外的值,或者应该调用但不是的。

编辑:

而且,如果您坐在机智的尽头,尝试修复该错误并在此处发布,希望您能获得一些闪亮的建议,请走开。抬起头,稍后再回来(最好是明天或周末之后)。我花了整整一天的时间寻找一个特定问题的解决方案,然后才走开,第二天清醒地回来,在十分钟之内找到它。


4
如果由于某种原因您不能使用调试器,则将一些跟踪信息放在您认为失败的代码段中,从而将函数调用记录到文本文件中。

3
为“走开” +1。要知道何时走开比敲开问题可能会更有效率,需要大量的经验。您的情况听起来像是开始收集特定经验的好地方。
Mike Sherrill'Cat Recall'11

如果您的软件需要断点来发现错误,那么您的大脑也需要它。这比强迫自己而不是走开通常节省更多的时间。
setzamora

我发现了一些日志记录功能,它们记录可能相关的值通常是跟踪此类情况的更好方法。用整洁的列设置日志行的格式,以便任何更改都引人注目。经常使用其调用来源的ID调用此日志记录功能。与逐步监视变量相比,您可以更快地检查日志文件。
罗伦·佩希特尔

10

调试更多地是要隔离和准确地了解问题所在(与应用修复相比)

调试时要注意的一件事是,如果您开始发现自己在追随不同的理论,因为这通常需要花费更长的时间,并且不能系统地消除可能的问题。

通常,调试此类情况的最佳方法是无聊的系统方法,方法是将您的系统分解成小块,并使每个部分孤立地工作,并逐一增加复杂性的每个元素,直到崩溃为止。然后,您便找到了确切的问题。这种方法可能看起来有些乏味,需要做更多的前期工作,但是在尝试调试复杂的软件时,它可以消除变量并保持头脑清醒。


5

这些只是我过去所做的事情,显然,它们不会在每种情况下都起作用:

  1. 要知道,这只是代码,并在某处有一个bug(它不只是黑魔法),您CAN解决。
  2. 休息一下。
  3. 非常缓慢地逐步执行代码,分析每个步骤并确保您了解它及其作用,而不是蒙蔽任何东西。
  4. 再看一眼眼睛,看看问题所在。
  5. 入睡,直到明天再忘记它(清醒头脑),换个角度来看)。
  6. 打印出代码,分析每一行,在空白处做笔记,了解每一行的含义
  7. 如果这不是一个严重的错误,但是会导致用户不需要知道的错误,那么我(羞耻地,但老实地)捕获了该错误并吞下了它!如果这不是危险的,并且您找不到原因,则有时您只是为此而困,并且不让用户知道发生了什么事。这全都是关于客户的投资回报率,有时这是不值得的。
  8. 口头告诉错误,您将要追杀并杀死它。有时它会消失。:-)

+1,因为它不是黑魔法!
盖·西顿

我们今天在代码中考虑了所有复杂的依赖关系,这是不可思议的。但您可以擅长
于此

3

解决错误时,我通常采用这种方法。

  1. 逐步创建一个不错的步骤来重现该错误
  2. 逐步简化
  3. 错误在代码中的何处发生?像涉及什么功能?
  4. 发生错误时,代码会选择哪种路径,即调用链。
  5. 专注于位置,什么时候可以,什么时候不可以。然后重复很多次,直到您准确找到发生错误的位置。
  6. 为什么会这样?

在这一点上,通常很清楚发生了什么事情,因为我在关注问题的过程中学到了很多东西,所以我知道该怎么做。或者,我有一个非常集中的问题,可以在论坛中提出。

然后,我尝试解决此问题,并使用您在第一步中创建的逐​​步方法来验证错误是否已修复。


3

以前的所有建议都是非常好的建议,其中很多建议旨在验证有关错误/错误的假设,然后遵循调试过程来定位错误(有时通过检查错误周围的环境,有时直接检查代码中的环境)。

无论您的资历或专业知识如何,这种方法都不会总是有效。有时,您只需要对问题有另一套看法。寻找某人与您一起检查问题或进行调试会话-通常只是通过代码交谈会导致您遇到错误。


我同意,这通常对我有用。
迈克·邓拉维

1

就像其他人所说的那样:1)能够可靠地重现它,并且2)在调试器中逐步进行直到发生它。

如果由于某种原因我无法做到这一点,那么我有另外两种方法都需要使用不同版本的代码,而这些版本均不会显示该错误。

  1. 在调试器下并排运行两个版本的代码。循序渐进,直到坏人做的事情与好人有所不同。

  2. 交替运行代码的好和坏版本。有DIFF或版本之间的差别其他一些列表。然后逐步更改任一版本的代码,以使其与其他版本更加匹配。如果坏的变成好,或者好的变成坏,我放弃更改并进行较小的更改。这样,我就可以发现该错误。我认为这是“从问题的两面出发并朝着中心方向努力”。此方法不需要调试器。

如果问题是难以重现,那么我需要尽可能多的信息,我可以得到的,比如一个堆栈转储,当它没有发生。因此,我确保可以得到那些诊断信息,等待问题发生,并希望我有足够的信息来找到它。


1

如果您被指派担任初级程序员的手头工作,那么至少会有一个人相信您有能力自己完成所有工作。

然后,在寻求上级帮助之前,写下便条纸,跟踪该错误的步骤/方法列表,执行该错误的程度,为什么放弃每种方法以及您学到了什么在每次尝试中。另外,总结一下到目前为止您对该项目学到的知识。

当您完成将其写下来时,可以做的事情很可能显而易见。如果是这样,您只需遵循显示的内容即可重现该错误,然后尝试修复。如果没有,您就有基础可以与您的上司进行交谈。如果您在不显示自己所做的事情的情况下寻求他们的帮助,他们可能会对您留下负面印象。

但是,如果您昂首阔步,在周末之后回来,您可能可以在没有任何人帮助的情况下立即解决此问题。它一直在发生。


“如果您被指派担任初级程序员的手头工作,那么至少会有一个人相信您有能力自己完成所有工作。” 在我工作时,所有开发人员都应寻求帮助,如果他们在做完自己的工作后还没有解决方案,那就叫做团队合作。
马腾兹

@mattnz我只建议在寻求帮助之前,将迄今为止所做的努力记录在案,并确保所有已知的选择都已用尽。我不知道该怎么称呼,但我从未质疑过您所说的团队合作。
vpit3833's

我想指出“ ...能够自己处理所有事情”,向我暗示您是一个人。很高兴知道我的解释比您预期的要强。
马腾兹

0

我们需要知道复制的难度,因为方法大不相同。为了可靠地重现缺陷,请自动导致缺陷。使用调试器和调试跟踪(跟踪对竞争条件类型缺陷的影响最小)。变得有条不紊。一次仅一步,每一步都提供更多信息,即使它正在确认您已经知道的信息。如果您得到意外的结果,请停止,在继续操作之前100%理解它。它的速度很慢,但是如果您给它足够的时间,它总是可以使您达到最终结果。

如果您无法解决问题,则有问题,如何确认已修复。放入调试代码,并将其保留在那里。最后,问问自己,“ Closed:DNR”是否有效?(没有/无法拒绝)。在业务中,最终是成本/收益的决定。

不要以为您的库是正确的,请确认它们是正确的。

稍事休息,务实应对成本与需要修复的问题,最重要的是,请其他人坐在您身边帮助您。


0

这里有很多好的答案。其他一些技巧:

UI很少独立存在。使用重现该错误所需的最少功能来构建测试程序。如果UI设计良好,则应该能够将出现故障的UI组件解耦,并在测试程序中单独运行它们。您还能重现问题吗?如果是这样,则问题可能出在您的UI结构或框架中。检查您的UI结构-特别要注意不可见的元素。尝试确切了解单击该ListView时无响应的情况-调用了哪些事件处理程序?请记住,UI框架本身可能存在错误-不要跳到这个结论,但也不要完全排除它。快速测试是升级您的Mosync版本,并检查症状是否仍然存在。

失败:测试程序中还剩下什么?了解剩下的所有组件,尤其是所有正在运行的线程。在后台进行数据库维护?某种文件假脱机程序?NSA用户行为监控代码?UI是否可以使用其中的某些组件(可能在幕后)?UI依赖哪些后台操作?

在阅读代码时-考虑到bug的困难,您应该花大量的时间-小心一些可能掩盖bug的不良做法。具体来说,您看到其中的任何一个吗?

try {
    SaveTheWorld();
} catch (std::exception& ex) { /* oh it didn't work, let's just ignore it */ }

这是非常糟糕的做法,因此相当普遍(嘿,它并没有崩溃!)。确保升级正在执行此操作的任何代码以至少将其记录-最好完全删除错误的异常处理。(一条经验法则是,如果您不知道异常是什么,就不准备处理它。)如果该异常与C样式的API交互,请注意是否留有错误代码返回值,并确保您正在从与之交互的任何工具中检查错误状态信息。

看起来您的测试程序现在如何正确地处理故障,并且您已经阅读了由此产生的日志,但是仍然没有任何内容可以突出显示该错误,请寻找可以探测的接口。幕后是否应该进行网络交易?如果是这样,请用Wireshark击中它。数据库事务?尝试一些查询日志记录,或检查数据库服务器状态。文件系统或网络共享受到打击?检查中间文件,或使用调试器跟踪I / O。硬件I / O?监视和探测。凭经验。UI可能会挂在您未曾预料到的某些后台操作上。

最后:不要惊慌。保持冷静,并跟踪您的尝试。如果仍然找不到它,那么它必须成为一个“已知问题”,以便在下雨天进行跟踪。如果必须这样做,您将需要大量材料来证明该决定的合理性。


0

在这种情况下,可重现的错误(相对)容易!为什么?因为您总是可以将代码缩减到最低限度,直到错误消失,然后再找出导致它的代码。这是一种方法。它是可复制的,您可以控制小动物。您可以戳一下,然后尝试一下。如果愿意,您甚至可以对其进行剖析。

你的第一个目标是要理解为什么这个错误是发生代码。最初不要尝试修复它。只是尝试了解它。如果您在不了解它的情况下尝试对其进行修复,即使您解决了它,也会四处乱逛,并且可能会引入技术债务

逐行逐步了解应用程序的行为。观察变量值。观察控制流。行为首先偏离您的理解告诉您应该在哪里?您了解操作系统如何将事件发送到您的应用程序吗?如果您受到“黑匣子”问题的困扰,是否可以获取已编译的库/框架的源代码,如果需要的话,可以使您更深入地了解它。

您的版本控制系统中有提交不会产生此错误的提交吗?(不是,您正在使用版本控制吗?)如果您确实有这样的提交,则可以对历史进行二进制搜索,以找出错误的确切引入位置。

您的目标应该是(1)了解-确定原因并为此目的,尝试(2)检查,详细了解应用程序的行为(3)通过消除问题来隔离问题,然后检查并了解导致使您能够做到这一点

但是如果您真的被卡住了,绝对不要坐在那里好几个星期。您还必须告诉组织中的某人。尽可能地寻求帮助,一定可以告诉管理层您感觉自己已经遇到了进步的障碍。但是,如果您从多个不同的角度来解决问题,而所有这些都集中在学习和理解上,那么您将可能解决该问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.