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

复杂软件的定义:

  • 包含由10多个开发人员在其一生中编写的代码,而不是在同一时间范围内编写的代码
  • 取决于10个以上的外部库,每个库有警告
  • 典型的软件任务(用于生成用户想要的结果)需要10个或更多输入参数,其中大多数具有默认值,但是如果用户需要控制,则可以配置。
  • 最重要的是,相对于要执行的任务具有适当复杂性的软件,即 并不是不必要的复杂.

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

冗余/鲁棒性的定义 在这个问题中:
(根据评论添加了鲁棒性)

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

此类软件的示例:

  • 数据库迁移
    • 业务数据库
    • 源控制数据库,等。
  • 在Word文档和OpenOffice文档,PowerPoint和OpenOffice Draw等之间进行批处理转换。
  • 整个网站的自动翻译
  • 软件包的自动分析,例如doxygen,但是分析需要更可靠(即不仅是文档工具)
  • 网络通信,可能会丢失数据包的地方,并预期会进行多次检索

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

可能相关:

有帮助吗?

解决方案

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

有时我正在与研究人员或原型编码,因此我们会以非常稳健的方式构建一些东西。如果破裂,我们将修复它。如果我们要尽快丢弃代码,那么投资额外的魔术是没有意义的。

但是,如果您的系统用户需要它可以强大,则应以这种方式构建它。而且,您应该以您和他们需要最大程度地提高长期成功的方式使其变得强大,同时忽略了他们不需要的冗余/鲁棒性。

通常,我开始粗糙,然后随着时间的推移添加健壮性。我经常提出像正常计划过程的这一部分一样的问题。我通常以极端的编程风格工作,在那里我们列出了一系列理想的功能,并且我也在其中放置了健壮的功能。例如,“系统可以在任何单个框的故障中幸存下来”,与“用户可以使用Facebook凭据加入”之类的东西混合在一起。首先,我先建造哪个。

其他提示

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

但是,如果您问我应该接受多少冗余,我会说什么。冗余是复杂性的众多副作用之一,即简单性的纪念性。可以说,如果时间更为重要,那么简单性应该倒退,尽管我强调说,那些认为时间本质上的人很少是那些实际上在开发软件上的人。通常,您的项目经理会尽快完成工作,以便您恢复更多紧迫的问题,但是作为程序员,您有责任知道何时完成工作。我认为,直到您将其成功地集成到计划中之前,这项工作才完成。也许该程序很复杂,但至少您的修改适合这种模式,从而使程序员习惯于看到类似代码的程序员有些容易理解。

但是,应该说这样做,您可能必须制作冗余代码。如果该项目已经高度多余,那么继续使用模式实际上可能更简单,假设您的老板没有几个星期的杀戮可以使您重组整个项目。

编辑:鉴于问题的重新提示,我将添加一些有关鲁棒性的信息。我认为,只有在a)您接受非常具体的格式(例如日期值)或b)可能相互冲突或相互排斥的各种参数时才应进行参数检查。

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

至于b),相互排斥的参数代表不良结构。应该有两个类,一个可以处理一个案例,另一种案例以另一种方式处理。所有常见的操作都可以在单个基类中进行,以避免冗余。

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

软件应宽恕用户错误,并且完全不容忍程序员错误。

含义,软件应该非常健壮,并允许对用户输入错误和系统配置错误等事项进行平稳恢复。至少在一条友好的错误消息中说明发生错误的位置(输入框,配置文件,命令行参数等)以及违反哪些约束(“必须小于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....

这只是其他不需要的复杂性。您不应该花时间定时来弄清楚如何通过滥用另一个功能来处理一个错误。如果这是您指的“鲁棒性”类型 - 您不需要它。用断言和彻底的集成测试代替它。

这是一件要求。

有鲁棒性需要吗?

“当通信链接失败时,丢弃错误的数据包”“当链接恢复操作时,没有处理两次交易”

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

将其留给程序员以发明稳健性(如果需要)产生“魔法”系统。

随着时间的流逝,所有魔法系统都会变得糟糕。背景中的误差校正隐藏了故障的发生,因此无法纠正故障,因此系统最终将降解为更大的熵状态。并像废话一样运行,因为它一直纠正错误。您必须有一个限制才能停止进入永久退化状态的系统。

某些操作可能需要采用“尝试”方法,尤其是当它们依赖于数据库之类的外部资源时。例如,如果数据库无法连接到或查询失败,则可以在放弃并将错误扔到更高级别之前进行一定次次数。但是,在某些逻辑上,多次尝试同一件事通常是不良代码和神奇思维的症状,它隐藏了真正的问题。

许可以下: CC-BY-SA归因
scroll top