第2章:IEC 62304 标准精讲
好,咱们进入正题。IEC 62304,这个标准在医疗软件圈子里,那就是圣经一样的存在。我当年第一次接触它的时候,说实话,头都大了。满篇的“shall”、“shall not”,感觉像在读法律条文。但干久了你会发现,它其实把软件开发中最核心、最容易出问题的地方,都给你圈出来了。
这一章,我们就来拆解它最核心的几个环节:软件生命周期模型、软件开发计划、软件需求分析、软件架构设计、软件详细设计。说白了,就是告诉你,一个合规的医疗软件,到底该怎么一步步“生”出来。
2.1 软件生命周期模型
标准不强制你用瀑布模型还是敏捷开发。它只关心一件事:你的流程是否可追溯、可控制。
我个人习惯,对于安全等级B级以上的项目,还是倾向于V模型。为什么?因为V模型把测试和开发阶段一一对应起来了。你想想看,需求分析阶段就要想好验收测试怎么搞,架构设计阶段就要想好集成测试怎么搞。这种“前后呼应”的感觉,在审核员眼里,非常加分。
当然,敏捷也能用。但我曾经在一个项目中,团队用Scrum做心电监护仪软件,结果每次Sprint结束,文档都补得想哭。审核员来了一看,问:“你们这个用户故事,怎么追溯到具体的风险控制措施?” 嗯,那场面,有点尴尬。
2.2 软件开发计划
开发计划不是写给老板看的,是写给审核员和未来的自己看的。标准里要求计划要包含:过程、交付物、里程碑、职责、以及如何应对变更。
这里有个坑,我踩过。有一次,我负责一个输液泵的项目,开发计划里写了“每周进行代码评审”。结果项目一赶进度,评审就变成了“大家看一眼,没问题就过”。最后测试阶段,发现一个死锁问题,就是因为评审流于形式。
所以,计划里不仅要写“做什么”,还要写“做到什么程度算合格”。比如代码评审,你得定义:必须由2名以上未参与该模块开发的工程师执行,且必须使用检查表。
| 计划要素 | 常见问题 | 我的避坑建议 |
|---|---|---|
| 过程定义 | 过程太粗,无法执行 | 细化到“谁、何时、用什么工具、输出什么” |
| 交付物 | 只列了文档名,没列模板 | 附上模板链接或示例,减少歧义 |
| 变更控制 | 口头沟通,无记录 | 所有变更必须走工具(如Jira),并关联风险分析 |
2.3 软件需求分析
需求分析,说白了就是搞清楚“软件到底要干什么”。但医疗软件的需求,比普通软件多了一层:安全需求。
标准要求,需求必须包含功能需求、性能需求、接口需求,以及最重要的——软件安全需求。这些安全需求从哪里来?从风险分析(ISO 14971)里来。
我记得有一次,一个呼吸机项目,需求文档里写了“当氧气浓度低于18%时报警”。这看起来没问题对吧?但审核员问了一句:“报警后,软件应该进入什么状态?是继续运行,还是强制进入安全模式?” 我们当时就愣住了。因为需求里没写。
所以,写需求时,我建议你多问自己几个“然后呢?” 把异常场景、边界条件都考虑进去。需求写得越细,后面返工的几率就越小。
2.4 软件架构设计
架构设计,是软件的高层“骨架”。标准要求,架构必须描述软件的组件划分、组件间的交互、以及数据流。
我个人经验,架构设计最容易犯的错误是“过度设计”和“设计不足”。过度设计,就是画了一堆高大上的UML图,但代码实现时根本用不上。设计不足,就是只画了几个方框和箭头,连接口协议都没定义。
我曾经在一个项目中,架构师画了一个很漂亮的“分层架构图”。结果开发到一半,发现底层驱动层和上层应用层之间,居然没有定义错误码的传递规则。导致上层捕获到错误后,完全不知道该怎么处理。最后只能临时加补丁,搞得代码一团糟。
所以,架构设计文档里,我建议至少包含以下内容:
- 组件清单:每个组件的名称、职责、所属模块。
- 接口定义:函数原型、参数、返回值、错误码。
- 关键数据流:数据从哪里来,经过哪些处理,最终到哪里去。
- 安全机制:比如看门狗、内存保护、异常处理路径。
2.5 软件详细设计
详细设计,就是把架构里的每个组件,拆解成具体的函数、数据结构、算法。标准要求,详细设计要详细到可以直接编写代码的程度。
嗯,这里要注意。很多团队觉得“代码就是设计”,所以不写详细设计文档。这在医疗软件里是行不通的。审核员要看的是,你的设计思路是否清晰,是否考虑了所有边界情况。
我习惯用伪代码 + 状态机来描述详细设计。比如一个按键消抖模块,我会这样写:
// 伪代码:按键消抖模块
// 状态:IDLE, PRESS_DETECTED, CONFIRMED
// 输入:raw_key_state (0/1)
// 输出:key_event (PRESS/RELEASE/NONE)
状态机:
IDLE:
如果 raw_key_state == 1 (按下):
启动10ms定时器
进入 PRESS_DETECTED
否则:
保持 IDLE
PRESS_DETECTED:
如果 10ms定时器超时:
如果 raw_key_state == 1:
输出 key_event = PRESS
进入 CONFIRMED
否则:
输出 key_event = NONE
回到 IDLE
否则:
保持 PRESS_DETECTED
CONFIRMED:
如果 raw_key_state == 0 (释放):
输出 key_event = RELEASE
回到 IDLE
否则:
保持 CONFIRMED
你看,这样写,开发人员拿到手,基本不需要动脑子就能写代码。而且,测试人员也能根据这个状态机,设计出覆盖所有路径的测试用例。
好了,这一章的内容就到这里。IEC 62304 的这些核心环节,说白了就是一套“防呆”机制。它逼着你在每个阶段都想清楚、写清楚、验证清楚。虽然过程繁琐,但等你真正遇到线上故障,或者面对审核员质询时,你就会感谢当初那个认真写文档的自己。