我刚刚遇到this question关于初始化局部变量的问题。许多答案都讨论了简单/可读性 vs。的健壮性。作为(远程部署)嵌入式系统的开发者,我总是喜欢稳健性,并倾向于遵循几个看似相互冲突的规则:
以允许设备继续运行的方式尽最大努力处理每个错误。
在编程或致命错误发生后,将代码设计为尽快。
我们都经过培训,可以验证输入,防止设备因用户(或其他外部)输入而中断;总是假设数据可能无效并相应地进行测试。
您还遵循了哪些其他特定的做法以确保健壮性?示例很有帮助,但我也对技术感兴趣适用。
答案 0 :(得分:7)
我喜欢“The Pragmatic Programmer”中描述的技术。我也使用TDD而不是DBC,因为我觉得它更灵活,更有效率。例如,'pragprog'中描述的一些技术包括:
它们看起来都是常识,但令人惊讶的是,当面临最后期限时,团队会迅速偏离这些基础原则。
答案 1 :(得分:6)
我喜欢第二双眼睛方法:在我编写并测试了一些关键代码之后,我有时会要求同事专门审查它以寻找打破它的方法。
以这种方式展现人们的创造力是很有趣的。 : - )
答案 2 :(得分:5)
听起来你已经把这两个下来了:
快速失败。 http://en.wikipedia.org/wiki/Fail-fast
安全失败。 http://en.wikipedia.org/wiki/Fail-safe
这三个人可能比任何其他人更好地服务于我:
尽可能避免状态。创建和使用不可变对象 - 它们更容易测试,更不容易背叛你。
不要写不必要的代码。这个很难。查看最近由Strunk和White撰写的关于“ The Style of Style ”文章的文章。
每10分钟左右问自己:“这个哑巴吗?”说实话。这个更难。
-Jason
答案 3 :(得分:2)
我尝试尽可能多地使用Design by contract。但我发现它在我的工作领域很少实用。
答案 4 :(得分:2)
我是不初始化局部变量的粉丝。它们应该在需要时设置。否则,阅读代码的程序员可能会像在"hmm why is this 0 at the beginning..."
中一样感到困惑。如果你没有初始化它,很明显它还没有被使用。
答案 5 :(得分:2)
我实施了各种方法来防止和从错误中恢复:
1)处理所有异常。如你所说,“处理每一个错误”。如果用户单击表单上的按钮,则应用程序不应该从未处理的异常中消失(“poof”)。出于这个原因,我使用通用的try catch包装事件处理程序。
2)使用完整堆栈跟踪记录错误。当我重新抛出异常时,我总是创建一个新异常并将捕获的异常添加为内部异常。我的日志记录代码递归地展开消息,这提供了比我更多的细节。
3)确定您的课程是否可以重复使用。如果不记录它。考虑在代码中实现一个接口,例如IRestartable
或IReusable
。任何没有实现它的对象在使用一次后必须丢弃。
4)永远不要假设线程安全。我已经学会了.NET非常多线程的困难方式。许多事件都是在任意线程上处理的。用.NET编写的给定应用程序可以执行许多同时执行的线程,并且没有一行代码明确创建一个。
5)保持变量范围尽可能窄。实例化在使用它们的位置附近的对象,而不是在方法开头的大块中实例化。您可能会缩短对象的生命周期,并且不会忘记位于类或方法顶部的大块中的不需要或重用的变量。
5)很简单,但我仍然看到它发生了。避免像瘟疫这样的全球化。我见过有数百个未使用/重用变量的代码。弄清楚和重构是一团糟。
答案 6 :(得分:2)
我喜欢...... 文档limit values in (java)doc 。 (参数可以为空吗?是空的吗?)
这样,当我使用我的代码时(或者当我使用自己的代码时),我知道我可以期待什么。简单推荐,但很少实施;)
该文件还包括static and runtime exceptions的明确分离。这样,如果程序必须尽快失败以提高稳健性,我知道它是否因为预见到的异常而失败(静态,必须在编码时通过捕获或重新抛出处理),或者如果这是因为参数不正确(运行时异常,仅在应用程序生命周期内检测到)。
如果明确记录了这两种类型的异常(特别是在限制参数值时),则整体稳健性更容易实施。
答案 7 :(得分:2)
如果可能的话,我会问一个专门研究其他事情的人的意见。这通常会揭示一种或多种全新的破坏方式。
答案 8 :(得分:2)
偏执狂是程序员的生存特质。不断问自己这怎么会失败?然后试着弄清楚如何防止这种失败。
答案 9 :(得分:1)
我写的系统(C语言)对性能和可靠性有很高的要求。设计失败是好的。当涉及到安全设计的设计变得更加复杂。
硬件总是会失败,除此之外,您还会遇到从外部进入系统的无效数据问题。我在这些方面的解决方案通常是精心设计的(安全设计),而在几乎所有其他领域,设计都是失败的,基本上只有极其简单的代码,而且根本没有数据验证。
所以你可以说我设计的风险很小时是失败的,而当它们很高时是安全的。
为了进行调试,我有时会写入条件代码,这些条件代码永远不应该输入,其中包含除以0或其他类型的条件代码,这样当处理进入那里时,调试器将立即被调用。
我通常不会初始化本地堆栈变量,因为编译器会告诉我哪些需要初始化,哪些可以完全省略。
代码审查很棒,但不是万无一失。我曾经花了几个小时看一个小的(无限的)循环(尴尬,不是吗?)并且看不到索引没有增加。我的同事也没有看到它。当我最终查看生成的代码清单时,我看到循环测试已经优化为单个无条件跳转,然后才明白问题是什么。