复杂软件应实现多少冗余/鲁棒性?


12

这个问题的焦点:尽管软件中存在一个或多个内部错误,某些软件执行“额外工作”以增加“最终成功/令人满意”结果的机会,当这些错误发生时,这需要更长的执行时间。如果结果成功,所有这些都会在用户不知情的情况下发生。

复杂软件的定义:

  • 包含超过10个开发人员在其生命周期内编写的代码(由其提供),并且未在同一时间段内编写
  • 依赖于10多个外部库,每个库都带有警告
  • 典型的软件任务(用于生成用户想要的结果)需要10个或更多输入参数,其中大多数具有默认值,但如果用户需要控制,则可以配置。
  • 最重要的是,相对于要执行的任务具有适当复杂性的软件,即不必造成不必要的复杂性

编辑:什么是复杂的?请参阅复杂和复杂之间有很大的区别(直接链接)

此问题内的冗余/鲁棒性的定义:(
基于注释增加了鲁棒性)

  • 如果在使用当前参数集时软件任务失败,请尝试其他参数。
    • 显然,必须有内部知识,这些“不同”的参数使用不同的代码路径,可能会导致不同的(希望更好)结果。
    • 有时,这些不同的代码路径是基于对外部库的观察而选择的。
  • 最后,如果执行的实际任务与用户的说明略有不同,则用户将收到详细说明差异的报告。
  • 最后,像10余个可配置参数一样,冗余和报告也是可配置的。

此类软件的示例:

  • 数据库迁移
    • 业务数据库
    • 源代码控制数据库等
  • 在Word文档和OpenOffice文档,PowerPoint和OpenOffice Draw等之间进行批量转换。
  • 自动翻译整个网站
  • 自动分析软件包,例如Doxygen,但需要更可靠的分析(即不仅仅是文档工具)
  • 网络通信,其中数据包可能会丢失并且可能会重试

这个问题最初是由您如何处理故意的不良代码启发而来的
但现在仅关注软件膨胀的原因之一。这个问题没有解决软件膨胀的任何其他原因,例如添加新功能。

可能相关:


5
那不是冗余,而是鲁棒性……

5
答案不是简单地“足够多”吗?
Dean Harding

@Dean-绝对,这是与其他任何要求一样的要求。诀窍在于解释它以及给用户带来的后果和成本,但是可以做到。
乔恩·霍普金斯

感谢@Thorbjørn的反馈。我在标题和定义中添加了鲁棒性。
rwong 2010年

除非您有5个孩子要养活,否则请远离旧的代码库。
Job

Answers:


7

这是一个业务问题,而不是技术问题。

有时,我正在与研究人员或在原型上进行编码,因此我们将构建鲁棒性很低的东西。如果损坏,我们将其修复。如果我们要尽快放弃代码,那么投资额外的魔术是没有意义的。

但是,如果您的系统用户需要它强大,那么应该以这种方式构建它。而且,您应该以一种特殊的方式使它变得健壮,而您和他们需要最大化他们的长期成功,而忽略了他们不需要的那种冗余/鲁棒性。

通常,我会比较粗糙,然后随着时间的推移增加鲁棒性。我经常在正常计划流程中提出类似此类的问题。我通常以“极限编程”风格工作,我们在其中列出了一长串所需的功能,并在其中放置了鲁棒性功能。例如,“系统可以经受住任何单个盒子的故障,”与诸如“用户可以使用Facebook凭据加入”之类的东西混在一起。无论哪个先出现,我都首先构建。


5

众所周知,复杂的软件通常多余的,但是显然不是因为这是最好的方法,而是因为开发人员倾向于“利用”现有代码,而不是尝试详细了解软件的工作原理。

但是,如果您问我应该接受多少冗余,那我什么也不会说。冗余是复杂性(简单性的根本)的许多副作用之一。可以说,如果时间更重要,那么简单性应该放在后座,尽管我强调指出,那些认为时间至关重要的人很少是真正关心开发软件的人。通常,您的项目经理会怂恿您尽快完成工作,以便您可以解决更多紧迫的问题,但是作为程序员,您有责任知道何时完成工作。我认为这项工作只有在您成功将其按计划集成到程序中之后才能完成。程序可能很复杂

但是应该说,这样做可能会产生冗余代码。如果该项目已经是高度冗余的,那么假设您的老板没有几周的时间可以让您重组整个项目,那么继续进行模式实际上可能会更简单。

编辑:根据问题的措辞,我将添加一些关于鲁棒性的信息。我认为,仅当A)您接受非常具体的格式(例如,日期值作为字符串)或B)各种参数可能相互冲突或互斥时,才应进行参数检查。

对于A),参数与特定格式匹配的要求通常对于方法的必要性(例如从字符串转换为日期)至关重要。从技术上讲,它不一定会在程序中发生,但我强烈建议您消除这些可能性,并仅接受您知道代表要查找的数据类型的参数(如果输入的是日期,则接受字符串,而不是字符串)例如,点不是要转换。如果还必须进行转换,请在将字符串传递给方法之前,使用实用程序方法对其进行转换。

对于B),互斥参数表示结构不良。应该有两个类,一个类处理一种情况,另一类处理另一种情况。所有通用操作都可以在单个基类中完成,以避免冗余。

在方法的参数数量达到10+的情况下,我开始考虑一个包含所有这些参数的属性文件,这些参数很可能不会经常更改。如果确实发生更改,则可以将默认值保存在属性文件中,并添加“ setPropertyName()”方法,该方法可让您在运行时覆盖默认值。


4
我认为您误解了这个问题。他的意思是“冗余”,如“发生错误时不死于火焰”,而不是“编写重复代码”。正如其他人指出的那样,健壮性是一个更好的名词。
亚当·李尔

在关键任务中,冗余是一件积极的事情。人体是这里的完美典范。
Claudiu Creanga

3

软件应该原谅用户的错误,并且完全不能容忍程序员的错误。

这意味着,软件应该非常强大,并且可以平滑恢复用户输入错误和系统配置错误之类的内容。至少有一条友好的错误消息,指出错误发生的位置(输入框,配置文件,命令行参数等)以及违反了哪些约束(“必须少于X个字符”,“有效选项为[X ,, Y,Z]“,等等。

我想不出很多情况下可以保证自动重试使用不同的默认值,但是有一些情况(自动重试以建立通信链接似乎是合理的)。我同意@William所说的“冗余”级别是一个商务决定。

另一方面,应该没有针对程序员错误的运行时鲁棒性。如果存在函数参数的前提条件,则应使用断言而不是运行时检查来检查它们。看到冗余错误检查并在调用堆栈中对三到四个级别的相同参数进行报告是我的一个巨大的烦恼:

 int A(int x)
 {
   if (x==0) return -1
   ...
 }
 int B(int x)
 {
   if (x==0) return -1
   err = A(x)
   if (err) return err;
   ...
 }
 // and so on and so on....

这只是不必要的复杂性。您不应该花时间确定一个函数应该如何处理由于滥用另一个函数而导致的错误。如果您指的是“稳健”类型,则不需要它。将其替换为断言和全面的集成测试。


3

这是要求的事情。

是否需要鲁棒性?

“当通信链接失败时,错误的数据包将被丢弃”“当链接恢复操作时,不会两次处理任何事务”

应该有用于错误恢复的用例(否则您如何知道它将如何发生?)

如果需要的话,让程序员去发明鲁棒性(如果需要的话)会导致“神奇”的系统。

随着时间的流逝,所有的魔法系统都会变成cr脚的魔法。后台的错误纠正掩盖了错误的发生,因此错误不会得到纠正,因此系统最终将降级为更大的熵状态。并像废话一样运行,因为它可以始终纠正错误。您必须具有限制,才能停止系统进入永久降级的状态。


2

某些操作可能需要“重试”方法,特别是如果它们依赖于数据库等外部资源时。例如,如果无法连接数据库或查询失败,则可以在放弃操作并将错误引发到更高级别之前重试该操作一定次数。但是,按照某种逻辑,多次尝试同一件事通常是不良代码和魔术思维的症状,这掩盖了真正的问题。


如果发生重试而没有被计数和报告/可见的情况,您的系统将由于其神奇的自我校正特性而降级并最终无法正常运行。始终使用漏斗计数器(PLOPD4)报告重试和错误。这样,低级别将被忽略,但是问题对用户变得显而易见。
Tim Williscroft
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.