嵌入式系统设计中你所不知的经验法则


本文为译文,原作者:PHILLIP JOHNSTON 菲利普 · 约翰斯顿,发表在Embedded artistry。
下文为节选原文章中个人感觉不错的地方,不足之处还请多多指教。

引言

​ 本文可称之为指导方针、启发法或经验法则。 但不管怎样,目的是相同的:提供一个合理的近似真理。 这些经验法则可以帮助您理解您所工作的系统,将您的注意力集中在正确的解决方案上,并突出潜在的问题领域。

通用
  • 保持一个系统运转比在系统崩溃后修复它要容易得多
  • 尽可能将错误从运行时移动到编译时
  • 没有文档的程序没有价值
  • 明显注释永远不应该重述代码的作用
  • 注释应该通过描述意图来帮助维护
  • 头文件中的所有内容都应该至少在两个源文件中使用
  • 通过消除干扰和中断,开发人员的工作效率会显著提高
  • 作为一个经验法则,你花在缺陷预防上的每一个小时将会减少你的修复时间,从三到十个小时
设计
  • 复杂的系统从简单的系统演化而来
  • 如果你不能用简单的语言描述这种行为,你就不能用代码成功地实现它
  • 将复杂的问题分解为较小的子问题
  • 一个函数应该只执行一个概念性任务
  • 不要解决不存在的问题
  • 解决具体的问题,而不是一般的问题
  • 设计是一个迭代的过程。 所需的迭代次数比当前完成的次数多一次。 这在任何时候都是正确的
  • 从来没有一个正确的解决方案,但总是有多个错误的解决方案
  • (爱迪生定律)“好”是“好”的敌人
  • (谢伊定律)改进设计的能力主要在于接口。 这也是把事情搞砸的首要地点
  • 研究发现,修改有缺陷的需求、设计和代码通常会消耗软件开发总成本的40% 到50%
  • 在最坏的情况下,一旦软件开始运行,重新处理软件需求问题的成本通常是在需求阶段重新处理问题所需成本的50到200倍
成本
  • 软件是昂贵的
    • “更新,2015年10月。 现在每行代码大概要花费25-50美元。 随着工资和对稀缺程序员的竞争加剧,外包到亚洲的项目成本大幅上升。” (菲尔 · 库普曼)
    • 一项又一项的研究表明,商业代码在所有没有记录在案的混乱中,每条线路的成本为15至30美元。 一个糟糕的1000行代码——并且很难在一千行中做很多事情——有一个非常真实的成本可能是30,000美元。 老话说‘这只是一个软件改变’ ,等同于‘这只是一块金砖’。” (杰克 · 甘塞尔)
  • 如果您想要降低软件开发成本,那么查看每一个需求文档并残酷地剔除一些功能特性
    • 功能特性繁多就等同于缓慢的进度和昂贵的开发
  • 一次性工程费用(NRE)成本必须平摊到销售的每个产品上
    • 通过减少功能来节省 NRE 费用
    • 通过将软件功能减少到硬件组件中来节省 NRE 费用,增加BOM成本
      • 只有当硬件已经存在时才有用
      • 应该在设计过程的早期评估软件 / 硬件分区
    • 通过更快地交付产品来节省 NRE
  • 完全重写5% 的有问题的函数,而不是修复现有的实现,这比较容易而且便宜
计划
  • 永远没有足够的时间去做正确的事情,但是不管怎样,总有足够的时间去重做
  • 评估日期而不是小时保证了一个晚期的项目
    • “当开发人员不把日历时间和工程时间分开时,日程安排灾难就不可避免”
  • 如果计划表产生了人员利用率超过50%的假象,那么项目就会成比例地落后
  • 我们往往未能预见到发展的困难领域
  • 5% 的功能消耗了 80% 的调试时间
  • 当将旧代码移植到新项目时,如果超过25% 的代码被修改,那么就不会有太大的进度提升
  • 系统加载占用了90% 处理器能力,比加载到70% 或更少的系统上多花2倍的开发时间。 如果95% 的加载则需要 3 倍的开发时间
    • 当只剩下几个字节时,即使是微不足道的特性也可能需要几周时间,因为开发人员必须重写大量代码以释放内存或 CPU 周期
  • 你制定的时间表看起来像是一个完整的虚构作品,直到你的客户因为你没有满足它而解雇你
  • 有时候,最快到达终点的方法就是抛开一切重新开始
  • (巴顿的计划规划法)现在大力执行的好计划胜过下周完美的计划
硬件
  • 增加硬件会增加功耗
  • 使用硬件加速器来卸载基于 cpu 的算法可以降低功耗
  • 每个传感器都是一个温度传感器,一些传感器还可以测量其他东西
  • 将讨厌的实时硬件功能分解为独立的 cpu
    • 从设备每秒处理1000次中断? 将其分割到自己的控制器上,并将所有 ISR 开销从主处理器上卸载下来
  • 只要能简化软件,就增加硬件
    • 这将显著降低 NRE 和软件开发成本,作为 BOM 成本增加的权衡
    • 系统加载占用了90% 处理器能力,比加载到70% 或更少的系统上多花2倍的开发时间。 如果95% 的加载则需要 3 倍的开发时间, 添加额外的硬件以减少负载(意思是加CPU、内存,就不用花大量时间进行算法代码优化了)
  • 当硬件运行良好时,真正重要的访问者不会出现
软件重用
  • 更喜欢使用已经被其他人重新使用过的现有的、经过评审的代码
  • 比起自定义通信协议,更喜欢简单、标准的通信协议
  • 遵循“三分律” : 允许复制和粘贴代码一次,但是当同一代码复制三次时,应该将其提取到一个新的过程中
  • 在一个包真正可重用之前,它必须至少被重用三次
    • 我们还不够聪明,不足以真正了解一大块软件可能被使用的应用范围。 每个领域都需要自己独特的特性和调整; 除非我们真正多次使用这些代码,在足够广泛的应用程序上使用,否则我们不会对它进行足够的概括,使它真正可重用
  • 在大段代码中进行重用效果最好——考虑重用整个驱动程序或库,而不是函数
优化
  • 过早的优化是浪费时间
    • “与其他任何单一原因(包括盲目的愚蠢)相比,更多的计算原罪是以效率的名义(不一定能实现)犯下的。”
    • 程序优化的第一条规则: 不要这样做。 程序优化的第二条规则(仅限专家!) : 先别这么做。
  • 只有在对代码进行分析之后才能对其进行优化,以识别问题区域
    • “瓶颈出现在意想不到的地方,所以在你证明瓶颈在哪里之前,不要试图事后诸葛亮,提高速度。” 罗伯 · 派克
    • “我们应该忘记小效率,比如说97% 的时间: 过早的优化是一切罪恶的根源。 然而,我们不应该错过这3% 的关键机会。 一个好的程序员不会因为这样的推理而自满,他会明智地仔细检查关键代码; 但只有在代码被识别之后才会”
  • Pareto理论可以应用于资源优化: 80% 的资源被20% 的操作使用
    • 另外,软件工程中也有90 / 10法则: 一个程序90% 的执行时间花费在执行10% 的代码上
  • 算法优化比微优化有更大的影响
  • 永远不要为了提高效率而牺牲透明度,尤其是当效率改进还没有被数据证明的时候
红旗及问题范畴
  • 当开发人员害怕更改一个函数时,是时候从头开始重写那段代码了
  • 复制代码是糟糕的设计或糟糕的编程习惯的表现,必须消除
    • “复制是一种不好的做法,因为它使代码更难维护。 当在复制代码片段中编码的规则发生更改时,维护代码的人必须在所有地方正确地更改它。 这个过程很容易出错,并且常常导致问题。 如果代码只存在于一个地方,那么就很容易在那里进行更改。”
    • ”此规则甚至可以应用于少量代码行,甚至是单行代码。 例如,如果你想调用一个函数,然后在它失败时再次调用它,那么有两个调用是可以的,但是,如果你想在放弃之前尝试五次,那么在一个循环中应该只有一个调用,而不是五个独立的调用。”
  • 尽可能避免共享资源
  • 消除全局变量
  • 禁用中断往往是一件坏事
    • 即使在最好的情况下,它也会增加系统延迟并可能降低性能
    • 延迟的增加导致错过中断和错误的设备管理
  • 提防单独的启用中断命令
    • 除了启动代码中的初始中断之外,位于中断之外的中断服务程序,通常比较危险
    • 如果 enable 不是 禁用中断 / 使能中断 对的一部分(这两个指令必须非常接近,以保持延迟降低和可维护性提高) ,那么代码很可能是令人费解的
  • 当代码中加入禁用中断/使能中断对时要小心
    • 过度使用禁用中断指令表明设计不良
    • “但是,当出现系统设计问题,导致大量关键区域容易出现可重入性问题时,这些禁用中断/使能中断对就会大量进入代码。 你知道这是怎么回事: 追踪一个 bug,勇敢的开发人员发现了一个被上下文切换丢弃的变量。 快速插入禁用中断/使能中断对。 然后是另一个。 再来一杯。 就像吸食海洛因的人吸了最后一口。 它永远不会结束。”
打断/中断
  • 除了嘴短暂的时间和最迫切的需要之外,不要打断别人的话
  • 如果在一段代码中禁用中断,那么应在同一段代码中重新启用它们
  • 中断服务程序(ISR)代码尽可能小巧
    • 注意不超过半页
    • 在大多数情况下,处理程序内部应该很少甚至没有处理
    • 设置一个标志,向队列添加一个值,然后依靠用户空间代码来处理更复杂的任务
  • 减小中断服务程序(ISR)延迟以确保系统不漏掉中断
  • 检查任何中断服务程序(ISR),在返回前立即重新启用中断
    • 减小中断服务程序(ISR)内的关键部分
    • “允许其他设备中断 ISR 是完全没有问题的! 甚至允许相同的中断这样做,给予足够的堆栈空间。 这意味着我们应该尽早创建处理所有不可重入内容(如服务硬件)的服务例程,发出 EI,并继续执行可重入活动。 然后弹出寄存器,再返回。”
  • 在中断处理程序中避免以下操作:
    • 不要在处理程序中声明任何非静态变量
    • 避免阻塞函数调用
    • 避免不可重入的函数调用
    • 避免任何占用大量时间的处理
    • 避免使用锁进行操作,因为这样会在 ISR 中使程序陷入死锁
    • 避免涉及动态内存分配的操作,因为分配可能需要一个锁并且需要不确定的时间
    • 避免堆栈分配
进一步阅读

译文不易,请多支持,更多延伸阅读,欢迎v关注我们【摄星科技】。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值