24

从我对固件工程工具、实践等历史的了解来看,它一直落后于软件工程领域好几年。例如,据我所知,固件世界仍然存在相当多的争论,即 C++ 是否真的值得用于我们的应用程序,并且一些 C++ 编译器明显不存在(微芯片?!?)。我想这在很大程度上是由于固件和软件之间的要求不同。同样,从历史来看,经过适当审查的工具和技术进入固件世界似乎只是时间问题。

现代软件工程师经常使用哪些方法、工具、最佳实践等,固件工程师还可以利用哪些方法来改进他们的工艺?

具体来说,我正在考虑以下轴(但不要让它们限制你):

  • 提高代码清洁度/可维护性
  • 减少缺陷引入并改进检测
  • 改进文档
  • 需求管理
  • 提高可重用性

我也很想看到嵌入式商店回答或评论答案,以提供有关理论可行性的反馈,或者更好的是个人经验。

更新
我对稍微领先一点特别感兴趣。所以相对较新的东西经过了相当好的审查(对大多数人来说效果很好),比如 C++、TDD 等。你一直在使用什么并且喜欢什么?

更新 2
到目前为止,我在答案中得到了很多很好的通用编程建议,这很好,但我真的在寻找更多已经证明对人们成功的非传统方法。我试图梳理一下敏捷实践者、TDDers 以及其他尝试过东西并看到它获得回报或惨败的人。作为一名软件工程师,您在过去几年中采用的工具或实践是否产生了显着的积极或消极影响?

4

9 回答 9

23

固件工程师可以从软件工程师那里学到什么?很多!

我很惊讶今天的固件开发与 25 年前我们第一次开始使用 C 进行嵌入式开发时的情况相似。C 是从汇编程序向前迈出的一大步,但固件工程师可以而且应该学习更多的经验教训。是的,有些工具更好,但很多做法都停留在 70 年代和 80 年代。

在非嵌入式开发人员面临的挑战之上,嵌入式软件开发确实增加了一些额外的挑战。但是熟练的软件开发人员使用的所有原则和实践都适用于嵌入式开发。顺便说一句:不仅仅是嵌入式软件开发人员不了解这些最先进的实践,许多非嵌入式软件开发人员也是如此。

我认识和遇到的做固件的人总的来说是一个非常熟练的团队,致力于解决难题。不幸的是,无论出于何种原因,许多人都没有跟上软件世界的发展。我认为这与固件工程师建立的想象障碍有关。

嵌入式和非嵌入式开发人员讲不同的语言,但解决类似的问题。保持嵌入式代码独立于硬件设备本质上与保持应用程序代码独立于 UI 或数据库相同。基本原理是一样的。

以下是我认为嵌入式开发人员应该更加关注的几件事。其中一些原则和实践可以直接使用,而其他原则和实践可能需要稍作调整才能应对嵌入的挑战。如果您想用下面的固件一词代替软件,请继续,我并没有真正区分两者。

依赖管理

必须管理模块之间的依赖关系。从软件到硬件的依赖是一种特殊情况,必须由嵌入式软件开发人员主动管理。如果您不管理依赖项,它将管理您。

在实践中,这意味着只有有限的软件模块子集应该了解底层硬件(和操作系统)。随着硬件的发展,并且总是如此,可以保留对硬件独立代码的投资。看我的啊哈!片刻。

Robert Martin 撰写了大量关于 SOLID 设计原则的文章。嵌入式开发人员应该了解它们并将它们应用到他们的设计中。

  • S-单一责任原则
  • O-开放封闭原则
  • L-Liskov 替换原则
  • I-Interface隔离原则
  • D-依赖倒置原则

这些原则导致设计更能经受时间的考验。SOLID 原则鼓励创建有凝聚力和独立的模块。它们建立在面向对象的思想之上,但可以应用于 C。我们必须停止在嵌入式 C 代码中太常见的函数调用数据结构免费。

C++ 和 OO 语言

为什么不能使用 C++ 和 OO?因为它们太慢或太大。事实是什么?C++ 是一种庞大而神秘的语言,但您不必全部使用它。看看你为什么还在用C?

C++ 弥补了一些 C 没有太大帮助的问题,例如:

  • 封装和信息隐藏
  • 接口编程
  • 可替代对象
  • 临时初始化

C++ 可以有效地用于嵌入式开发。好吧,您确实需要一个 C++ 编译器和余量。也许这在你的世界是不可能的,或者是做生意的成本。从学习开始:

  • 类 - 这些是具有成员函数和成员数据的结构。
  • 构造函数——这些使得初始化正确成为可能,一直都是。
  • 析构函数——如果你学习构造函数,你还必须学习析构函数以保持宇宙的平衡。
  • 继承 - 主要用于定义仅包含纯虚函数的接口。接口提供了重要的依赖中断和灵活性点。这些通常在嵌入式中被不公正地劝阻。这里不应该有任何神秘或偏见;虚函数是底层的函数指针。有效使用接口的替代方法是复杂的条件逻辑,嵌入式 C 程序通常有太多的东西。

如果嵌入式开发人员使用 C++ 的这些部分,他们可以构建更灵活的设计并且不会产生高昂的成本。

测试驱动开发

这可能是最大的游戏规则改变者。我很高兴看到其他帖子也提到它。TDD 可以帮助预防现在和将来的缺陷。要了解为什么 TDD 可能有助于查看 TDD物理学

嵌入式确实给 TDD 带来了一些独特的挑战。例如,TDD 需要极快的增量编辑/编译/链接/运行周期。对于许多嵌入式开发人员来说,这意味着仔细的依赖管理并首先在目标上运行单元测试。查看更多关于 为 Embedded 调整 TDD 的信息

使用 TDD,您正在创建经过彻底测试的代码。全面的自动化测试覆盖率充当安全网,允许随着需求的变化安全地更改代码。意想不到的后果立即被发现。

此外,拥有几乎免费获得的测试,让您可以无所畏惧地重构您的代码......

持续重构

代码只写一次,但要读很多次。然后它被改变和调整,导致设计随着时间的推移而退化。如果开发人员不不断地重构以保持代码干净,就会变得一团糟。也许你们中的一些人正在处理这个烂摊子。TDD 的自动化测试支持低成本和低风险的重构。

持续集成

自动化您的构建过程。让它在每个工作区签入时运行。对于将编译后的代码导入目标所需的异构工具集来说,这是一个挑战,但它仍然是正确的目标。

嵌入式开发人员越早知道某个更改在某种程度上与其他工作不兼容,修复它的速度就越快,花费在痛苦合并上的时间就越少。

增量交付

寻找拆分工作的方法,这样就可以避免大量痛苦的集成,并且可以及早尝试设计理念。避免沿着架构线分裂,专注于提供可见功能的切片。

合作

嵌入式开发者!离开那里的立方体并一起工作。当您只看到自己的代码时,如何才能变得更好?当您是技术 XXX 方面的专家,已经掌握了它并且没有机会在不同的领域工作时,您将如何改进。

那里有很多东西要学。你有责任尽你所能

于 2009-07-28T21:58:46.800 回答
15

我曾担任嵌入式软件工程师和软件开发人员。在这两个世界中,我了解到,无论您的系统资源多么少,您正在编程什么语言,都有很多事情可以让您的生活更轻松。

首先是您使用的工具。在嵌入式软件中,您大部分时间只处理编译器/链接器。不止这些。差异工具、正则表达式、脚本语言、文档工具可以为您节省大量时间。

另一件事是代码质量。需要遵循样式约定,经历定期的重构周期,并且通常要记住代码阅读比代码编写更频繁,并且拥有更多可读代码确实值得。

在嵌入式软件中,有时我们会完全错过设计阶段。嵌入式项目通常没有桌面/服务器项目那么大,但这不是不进行适当设计的借口。

软件需要单独进行测试,而不仅仅是作为设备的一部分。为您的系统构建软件模拟器确实节省了大量时间,仅用于测试软件是否符合要求的规格。当整个事情、硬件和软件都准备好时,这样做的成本要高得多。

于 2009-07-24T12:10:15.427 回答
7
  • 源代码控制
  • 单元测试 (TDD)
  • 持续集成(或夜间构建)
  • 错误跟踪

我合作过的固件工程师不做这些。

单元测试可能并不适用于所有类型的固件。当它在物理硬件上运行时,我认为它更难对某些东西进行单元测试。我想取决于您是否有可用的模拟器。

于 2009-07-24T11:56:58.603 回答
5

假设“固件工程师”的意思是“嵌入式软件工程师”,那么我的回答是:他们软件工程师,所以他们应该 - 在可能的情况下 - 做与任何其他软件工程师相同的事情。

显然,为嵌入式系统编写软件需要一些不同的技能,例如目标处理器的详细知识,以及能够处理有限的资源(与 PC 或类似设备相比)。

正如其他人所提到的,单元测试很复杂,因为这可能必须在 PC 上运行的模拟器上完成,这虽然非常有用,但永远不能替代对真实系统的彻底测试——尤其是考虑到异步性质嵌入式系统所受的事件。

关于为什么嵌入式软件可能看起来“落后”,我的一个担忧是因为软件工程——作为其中的一部分,嵌入式软件——通常没有深入地教授电子工程学位。考虑到如今电子工程师的职业生涯有多少可能花在编码上,这似乎是一个巨大的疏忽。

幸运的是,有些人正在努力弥补这一点。我强烈建议阅读 Jack Ganssle 的文章(在他的网站上,以及在嵌入式.com 上的常规专栏中)。

此外,MISRA-C是不久前创建的,旨在避免汽车行业 C 软件中常见的错误来源,此后被嵌入式软件领域的许多人采用。添加一个像PC-Lint这样的静态分析检查器,您已经采取了一些方法来改进您的代码。

工具供应商也没有提供帮助,在许多情况下,他们创建了自己的 IDE,而将注意力集中在编译器和调试器上,而将 IDE 留给其他人(例如 Eclipse)可能会更好。

顺便说一句,有关在嵌入式系统中不使用 C++ 的更多信息,请参阅此问题

最后:因为固件工程师是软件工程师,我们面临许多相同的问题、挑战和担忧,所以我们应该使用相同的资源;毕竟,周围有很多,而您正在阅读其中之一!

我经常访问的其他一些网站包括:

编辑:为了回应 Gabe 的评论,“我们应该寻求适应哪些工具?”,我想到了几个例子:

独立于编译器的 IDE:很多用于 C 的 IDE,但据我所知,如果没有兼容的编译器,它们中的少数几个可以发挥其有限的潜力。我希望看到编译器开发人员和 IDE 开发人员融合在一起,这样,理想情况下,任何编译器都可以与任何 IDE 一起使用。

在没有兼容的编译器的情况下,我希望能够使用 PC-Lint(或等效的)作为我的“官方”编译器和我选择的 IDE。

仿真和建模:Simulink等仿真工具允许对 PC 和一些高端嵌入式处理器的软件进行仿真、建模和测试。像这样的工具对于较小的芯片同样有用,所以很高兴看到它们扩展到市场的那个领域。

PS:Jack Ganssle 本周的专栏标题为“是什么让嵌入式与众不同? ”,因此与上述问题(松散地)相关。

于 2009-07-25T17:38:23.180 回答
3

不确定什么程度的软件被视为固件(bios、驱动程序或实用程序),但我听到的标准抱怨是 UI 是非标准的。意识到 UI 很重要并且它应该遵循一些标准或传统将是一件好事。

就 C++ 而言,犹豫不决是可以理解的,因为与 C 相比有很多开销。C 几乎就像带有 libc 的汇编语言,而在 C++ 中,即使是简单的函数调用也可以是虚拟的。鉴于语言的复杂性,实现完整的 C++ 运行时并不容易。

就软件开发“最佳实践”而言,要列出的东西太多了(我讨厌这个词)。为什么不从乔尔测试开始:更好的代码的 12 个步骤。

乔尔测试

  1. 你使用源代码控制吗?
  2. 您可以一步构建吗?
  3. 你做日常构建吗?
  4. 你有错误数据库吗?
  5. 在编写新代码之前你会修复错误吗?
  6. 你有最新的时间表吗?
  7. 你有规格吗?
  8. 程序员有安静的工作环境吗?
  9. 您是否使用金钱可以买到的最好的工具?
  10. 你有测试人员吗?
  11. 新候选人在面试时会写代码吗?
  12. 你做走廊可用性测试吗?
于 2009-07-24T12:02:02.247 回答
2

固件工程相当广泛。从 PIC 到 DSP,它们都有不同程度的物理资源。如今,DSP 非常强大(与大约 5 年历史的 CPU 相媲美),可以支持大量内存等。但是你又可以使用几千字节运行的 PICS。资源越少,程序员就必须使用巧妙的技巧来充分利用设备。重点是“让它工作”而不是“编写优雅的代码”。

我希望看到的是优秀的项目管理工具,其中包含代码和文档,因为您必须参考大量数据表、分散在网络和电子邮件 blob 上的设计文档等。

我还希望看到更好的 DSP 开发工具(TI:请将 CCS 交给擅长制作 IDE 的人),以及更多使用 C++ 的库制造商(我正在寻找你的 ATEME)来构建更好的库。

硬件工程师也要更好地理解面向对象,而不是脱口而出,“如果是 C++,它会很慢”。

于 2009-07-24T12:11:23.037 回答
2

让我首先解决您问题中的一个假设。假设是嵌入式软件工程师 (ESE) 不知道或不了解现代软件工程实践并且需要学习新的实践。这个假设应该立即被抛弃。我相信您会发现 ESE 的统计分布与非嵌入式 SE 一样,他们保持他们的技能和技术是最新的。

因此,也许您的问题会变成一系列问题,例如:

  1. 为什么 ESE 使用单独的代码编辑器和命令行编译器而不是 IDE?
  2. 为什么在大多数嵌入式项目中 C 优于 C++?
  3. 为什么在嵌入式世界的编程实践中没有那么多实验?

以下段落回答了这些问题。

  1. ESE 通常使用特定的代码编辑器,因为这是个人喜好或他/她的公司使用的。IDE 并不常见,因为 ESE 与硅的工作非常密切,而且并非所有芯片制造商都为他们的芯片系列开发 IDE。只有实现最高市场渗透率的芯片,如 ARM,才有足够的动力来保证基于 IDE 的工具的开发。此外,IDE 对 ESE 的帮助不如对桌面开发人员的帮助多。IDE 为大型 API 提供了与 GUI 的粘合或代码完成的帮助;两者都不常见,也不像嵌入式世界那样标准。

  2. 我敢肯定,关于为什么在嵌入式系统中 C 比 C++ 更受青睐,我肯定有比我能在现场弥补的更好的文章。简而言之,您使用有效的方法。C 可以工作并且更常见(比 C++ 了解 C 的程序员更多)。另一个原因可能是 OO 方法旨在通过将解决方案抽象为可管理的概念对象来帮助程序员解决大问题。在嵌入式世界中,问题通常被缩减为尽可能小的问题(和解决方案),以便嵌入式系统通过更小的代码库变得更加可靠。

  3. ESE 的实验较少,因为嵌入式产品通常比桌面程序更不容易出错并且具有更高的可靠性。这意味着严格应用经过充分验证的实践并花费更多时间进行测试。为什么?因为通常没有可行的途径来升级嵌入式设备的固件;这要么是不可能的,因为系统被部署在遥不可及的地方,要么是因为更新数百万台设备的成本而难以置信。

总之,ESE 使用最适合其需求的工具和实践,就像非嵌入式 SE 一样。 作为一名 ESE 实践者,我相信嵌入式软件学科与我的非 ESE 朋友所认为的相差甚远。因此,编程实践的明显差异不是 ESE 需要学习现代实践的问题,而是非 ESE 需要了解嵌入式编程的不同之处。

于 2009-07-26T14:43:26.027 回答
2

自动化测试
不要目视扫描您的模拟输出以检查一切是否正常。您需要全面的自动化测试,因为您总是会错过大量波形中的某些内容。

版本控制
你不会记得工作版本是什么。使用版本控制软件,这样您就知道用什么对该板进行编程。

错误跟踪
你迟早会忘记的。错误日志应包含首次检测到问题的版本(请参阅版本控制)以及修复问题的版本。

哎呀,我以为您指的是 FPGA 中的固件,但嵌入式软件也是如此。如果您已经准备好这些流程,那么在掌握基础知识之前就别想了unconventional approaches

于 2009-07-27T06:43:19.497 回答
0

这可能有点脱离上下文。对Embedded
上的固件专栏的简短参考,

我一直在 Embedded 找到关于固件工程的好文章。
可能许多对这个问题感兴趣的人也...

于 2009-07-27T18:20:35.960 回答