返回列表
工程

设备控制软件开发的若干建议

设备控制软件运行环境与常规软件不同 — 调试器最少化、日志策略、条件式编写规范、兼容性考量。多年现场总结的实战经验。

6 分钟阅读· ICT Engineering

设备控制软件开发与一般软件开发存在不同的环境约束。运行在量产设备上的代码的特殊性,以及一次失误带来的代价,让下面这些建议年年值得复读。


设备控制编码建议

设备控制 SW 开发有其特殊环境,以下方面与一般软件开发不同:

  • 调试器最少化 — 设备运行时几乎无法附加调试器。请充分利用日志,并锻炼快速阅读源码的能力。
  • 结构设计 — 先看大图,落到代码时再聚焦细节。
  • 客户需求分析 — 不要只看表面请求,花时间找出根本原因
  • 导出共同条件 — 寻找能涵盖多种条件且抓住核心的简单共通条件,可以减少分支。
  • 修改的副作用 — 一处修改可能引发十处问题。多加一个 checkbox 选项,测试用例与 bug 都会翻倍。
  • 代码分支成本 — 同一台设备分两份代码维护,工作量增加 1.5 倍,但维护成本和 bug 翻倍。
  • 新驱动测试 — 新增驱动先在一台设备上充分测试,再投入到量产设备。
  • 发布清单 — 不要只发布可执行文件,确认版本升级所需的新增文件全部包含在内。
  • 日志策略 — 关键条件、时序、数据务必记录日志。异常路径下尤其必要。无意义的日志请及时清理。
  • UX 基础 — 归根结底,对使用者的体贴最重要。

条件式书写原则

让读者按自然顺序读出语义。

  • 最大的前提条件放前面。
  • 同一层级时,把更不容易为 true 的条件放前面(短路求值更快、更早失败)。
  • 不要使用整体否定 !(...) — 读者得在脑子里再翻一次。
// GOOD
if (A == false && B == false && C == false) { ... }
 
// BAD
if (!(A || B || C)) { ... }

比较表达式中,把变量放在左边,常量放在右边 — 与自然阅读顺序一致。

// GOOD
if (A > 2) { ... }
 
// BAD
if (2 < A) { ... }

返回指针的函数设计

返回指针的函数在出错时若返回 NULL,调用者很容易漏掉空检查,结果通常是设备停机

  • 尽量返回有意义的 Dummy 数据指针,让程序不至于挂掉。
  • 必须记录日志,以便追踪哪里触发了 fallback。

UI / UX

  • 添加 XEdit 等输入控件时,设置合理默认值。空字段会迫使用户每次都重新填入。
  • 未保存时离开画面,应让数据自动还原。"不保存" 的预期行为必须一致。

管理与优化

  • 客户的要求过于轻易答应,它们就会成为理所当然的标准
  • 一旦发现重复代码,立即提取为函数。拖延一下,两份代码就会发生分叉。
  • Include Path 应配置在每个项目中,而非全局。降低环境依赖。
  • 项目过半后,就应开始考虑退出策略(交接、文档、日志整理)。

日志与可搜索性

日志中写函数名时,不要加括号 () — 会降低搜索效率。

// GOOD
LOG_PRINTF("", "DoFunc 执行中");
 
// BAD
LOG_PRINTF("", "DoFunc() 执行中");

兼容性与场景

  • 添加功能前,先考虑与现有数据的兼容性对量产设备的可应用性。数据迁移的成本经常被低估。
  • 时序出现问题时,在能清晰复现时序与场景之前不要停止追查。"偶尔会发生" 在量产后只会更贵。

开发工具与语言

请使用强大、便利的开发工具与语言。

  • 通用: Visual Studio (C++, C#)
  • 控制专用: BeckHoff TwinCATCodeSys
  • ICT 自研一体化控制 IDE: QMachineStudio — 时序、GUI 与运行时调试集成在一起。

好的工具与强大的语言,会显著提升开发效率。即便已经习惯当前的工具链,也建议定期审视开发环境。

PC 控制自动化编码规范调试设备开发