The Power of Ten: 安全关键编码规则
摘要
一位 NASA/JPL 研究人员讨论传统编码标准的不足,并介绍“The Power of Ten”规则,通过简单性和指标驱动实践来预防安全关键软件中的缺陷。
<p><a href="https://lobste.rs/s/aecolw/power_ten_rules_for_safety_critical">评论</a></p>
查看缓存全文
缓存时间: 2026/08/27 07:34
# 十的力量:安全关键编码规则
**概要:** NASA/JPL 研究人员探讨了以指标驱动的软件可靠性、大多数编码标准的失效,并引入了"十的力量"规则来防止任务关键代码中的灾难性缺陷。
## 引言:为何安全关键标准会失效
2003 年,离开贝尔实验室后,我加入了 NASA 喷气推进实验室(JPL),负责深空任务的软件可靠性工作。JPL 曾因软件异常损失过任务,我最初的职责是调查现有的软件安全标准,以期改进我们的飞行软件。
我很快发现了一个关键缺陷:JPL 的每个项目都根据任务负责人的个人偏好制定自己的编码标准,而不是基于任何已确立的框架。这反映了行业内一个更广泛的问题。正如 Andy Tanenbaum 所言:"标准这么多,随你挑。" 我收集的标准涵盖了从空白字符(制表符与空格)到复杂逻辑的方方面面。许多规则完全无法检查,即使是流行的规则,在没有工具强制的情况下也经常被忽视。最终,这些标准主要让人"感觉良好"——感觉自己有了标准,却并未真正提升可靠性。
## 软件缺陷的现实
NASA 自己的指南指出了一个令人警醒的事实:**必须假定所有软件都存在缺陷。** 安全必须从设计之初就考虑;它无法在后期通过测试实现。
来自 NASA/JPL 指南的关键点:
* 大多数现代软件,尤其是多线程或分布式系统,无法进行穷尽测试。
* 覆盖率指标如 MC/DC 或分支覆盖率是不够的;它们仅仅触及了潜在故障模式的表面。
* 经过精心测试的软件,其发布后的平均缺陷率为 **每千行代码(KLOC)1 到 10 个缺陷**。例如,火星科学实验室(好奇号漫游车)拥有 300 万行代码,意味着存在数千个残留缺陷。
* 对于任务安全关键代码,缺陷率必须低几个数量级——这只能通过设计实现,而非测试。航天飞机流程实现了大约 **每 KLOC 0.1 个缺陷**,但从未达到零。假定零缺陷会导致危险的自满情绪。
* 即使是微小的缺陷也可能是灾难性的(例如福岛第一核电站事故),尤其是在故障保护软件中,因为不可预见的故障组合是难以想象的,这部分代码也是测试最不充分的。
## 最重要的实践:收集指标
指标是提高软件可靠性的唯一最重要活动。缺陷在开发过程的每个阶段——需求、设计、编码和测试——都会被引入,并可能传播到后续阶段。目标是在缺陷引入的阶段就将其检测出来。
例如,AT&T 的开发数据显示了不同阶段每千行代码的缺陷数。我们关注的指标是泄漏到下一个阶段的缺陷数量;我们希望这个数字为零,尽管它永远不会是零。分析大多数缺陷被引入的原因以及为什么没有更早发现,是流程改进的关键。
**软件可靠性不仅仅是发现和修复缺陷。** 每发现一个缺陷,都揭示了开发过程本身的一个缺陷——一个本应更早被捕获的错误,或一个允许其引入的流程缺陷。
## 可靠软件的核心原则
### 强调简单性
复杂性是可靠性的敌人。一个简单、结构良好的系统远比复杂的系统更容易维护和调试。在 JPL,人们对风险有着深刻的认识;没人想成为那个因缺陷导致任务失败的人。这种文化意识强化了对简单性的要求。
### 使用语言限制和强指导原则
禁止那些在统计上容易导致缺陷的语言特性。一个主要例子是 **动态内存分配**。代码结构应确保一个模块中的缺陷不会导致整个系统崩溃。这需要严格遵守 **契约式设计** 原则——前置条件、后置条件和不变量。
### 自动化强制执行
如果一种缺陷类型没有被自动检查,它就会溜走。使用工具来强制执行规则。我最喜欢的工具是 **Cobra**,一个开源的、快速的、可编程的静态源代码分析器,可以定制来检查"十的力量"规则。
## 失败的根本原因:一个目录
我汇编了一份关于任务失败和软件导致问题的综合列表。令人惊讶的是,大多数问题仅归为 **六大类**:
1. **基本编码错误:** 可通过更严格的指导原则来预防。
2. **设计问题:** 系统架构中的缺陷。
3. **内存使用:** 尤其是动态内存分配。
4. **线程问题:** 多线程代码中的死锁、竞态条件。
5. **代码复用:** 不加考量地复用先前任务的代码,而未顾及新环境,是一种常见但错误的做法。
6. **故障保护:** 错误恢复代码本质上是测试最少、最脆弱的部分。
## 十的力量:安全关键编码规则
基于对这些失败类别的分析,制定了十条编码规则。其理念不是盲目遵循某个标准,而是采用一套小而影响大、可验证的规则。目标是编写如此简单和受限的代码,使其行为可预测且缺陷极少。
这些规则直接对应六大根本原因。它们强制要求采用诸如以下的做法:
* **限制控制流** 仅使用简单构造。
* **避免动态内存分配** 和递归。
* **编写带有强断言的函数接口**(契约式设计)。
* **使用定点算术** 代替浮点算术以实现确定性行为。
* **执行有限的数据和调用嵌套** 以降低复杂性。
这些规则设计为可由 Cobra 等自动化工具检查。如果一条规则没有被工具强制执行,它就会被忽视。通过遵守这些约束,代码变得更加可预测、更易于验证,最终对于最关键的任务而言更加可靠。
**来源:** 十的力量:安全关键编码规则 (https://www.youtube.com/watch?v=GRJtYwneG2Q)
相似文章
@0xDepressionn: Karpathy的4条规则将编码准确率从65%提升到了94%。大多数开发者都没读过。读过的人总结了21条规则…
Karpathy关于编码准确率的四条规则将性能从65%提升到了94%,一个汇总了21条规则的GitHub资源已经吸引了82,000名关注者。
@nateberkopec: 自动 lint 规则,对人类来说过于严格,但对代理有效:1. 圈复杂度预算 2. 每文件代码行数限制…
这条推文讨论了像圈复杂度预算和 CSS/JS 限制这样的自动 lint 规则,这些规则对人类来说严格,但对编码代理有效。Sam Saffron 强调了它们在防止长期代码腐烂方面的作用。
征服熵:培育信任
本文强调了在工程团队中对AI生成代码建立信任的必要性,并概述了诸如问责制、编码指南和确定性工具等实践,以维护代码质量。
@mattpocockuk: "我同意软件基础很重要。但哪些基础?以什么顺序?"我的答案:
Matt Pocock 分享了他优先考虑的基本软件基础列表,强调学习阅读代码、使用终端、通过类型和测试防止错误、为更好的测试构建应用,以及应用 DDD 中的通用语言。
@SaitoWu: https://x.com/SaitoWu/status/2053101671035851216
The article summarizes a talk by Matt Pocock criticizing 'specs-to-code' approaches, arguing that solid software engineering fundamentals like TDD and modular design are more critical than ever for effectively using AI coding assistants like Claude Code.