以下文章来源于汽车ECU开发 ,作者eng2mot
汽车ECU开发
专业 有趣 认真,做一个有价值的公众号
在汽车新四化的背景下,软件无可置疑的是汽车发展的核心部分。然而随着功能的不断增加,潜在的软件复杂性也在逐渐的增长,但是由于软件的不可见性,导致工程人员对软件复杂性的重要性不能充分理解。然而随着时间推移,软件复杂性将以大量缺陷报告、维修成本激增的形式呈现出来。对于软件的复杂性,通常想到的就是软件的大小,但是并不是所有大型软件都很复杂。不过软件大小也是表示软件复杂性最直接的属性。软件大小通常用代码行数来表示,这样就可以把软件复杂性形象化,利于大家的理解。例如一行代码相当于书中的一行文字,假设某个ECU软件的大小为300页,每页50行,而简·奥斯汀的《傲慢与偏见》刚好差不多这个数,这样人们就可以将该软件的大小类比于《傲慢与偏见》。沃尔沃表示,至2020年,其旗下汽车的代码行数约为1亿行,这意味一辆车上的代码行数相当于6000本普通图书,够城镇图书馆的馆藏,这1亿行代码实现了电子燃油喷射、传动控制、发动机控制、巡航控制、动力系统控制、自适应悬架、多路网络、导航系统、稳定性控制、信息娱乐、避碰、高级驾驶员辅助系统、主动安全、互联以及许多更先进的功能。统计表明,从2000年开始,汽车软件的大小每10年增长一个数量级。下一个10年,随着万物互联和自动驾驶功能的加入,到2030年,汽车上软件的大小将达到麻省理工大学科幻小说社会图书馆的馆藏数。
一个系统的复杂性是由系统元素数量和类型以及交互构成。复杂性是赋予系统功能和特性的基本要素,但是复杂性也是造成系统难以理解的原因。在代码中,运算符、局部变量、全局变量、条件语句、预处理、指针、函数调用等数百万个元素的相互连接创建了复杂的单元和大规模的抽象层。此外,代码与相应的软件版本、需求、测试、变更和电子组件的依赖关系在汽车软件中造就了惊人的复杂性。然而。复杂性通常是由于非优化设计决策和未意识到的业务需求而在系统中积累起来的。这种复杂性并不能增加软件的功能;但是会消耗了大量的工作并产生软件缺陷。那从软件层面来看,复杂有哪几方面呢?下面就一一道来。沃尔沃的统计显示,到2020年,整个源代码中有1000万条条件语句。这些是决策块和循环块。在整个源代码中定义了大约300万个函数,这些函数在源代码中大约3000万个位置被调用。这些功能中的许多在车辆运行时执行任务。函数产生错误结果的概率取决于程序员的技能、代码的整洁性、测试的质量等等。即使概率非常小,例如0.0001,开发后缺陷仍然会数以百计。这不是因为开发人员不熟练,也不是因为测试不好,而是因为总的复杂性是惊人的。巨大的复杂性纯粹是有可能产生缺陷的。函数调用和条件语句引入了基本的复杂性。这些元素对于编写一段代码来解决问题是必不可少的。更令人生畏的是偶然出现的复杂性,特别是祖传代码的复杂性。20-30年前编写的代码引入了深度嵌套的代码区域。对嵌套的统计,显示汽车上20%的功能中,最原始的功能区域嵌套次数很高。构建在其原始框架之上的新代码将成为冗长讨论的来源,旧代码应该被重构还是保持不变?随着人们越来越意识到高复杂性的影响,软件工程师越来越重视开发简单代码。遵循编码准则已经成为比以往任何时候都更加严格的实践。一段代码不能合并到主代码分支,除非它符合复杂性管理准则;深度嵌套的代码、交叉信号、指针和全局变量的不正确使用、不一致的名称、冗长的行以及其他意外的复杂性触发都将被拒绝。尽管静态分析工具并不完美,但它们试图系统地帮助工程师完成这项任务。遗留代码经过彻底测试,并尽可能保持隔离和不变。统计显示,在一辆现代沃尔沃汽车中,大约有7000个外部信号连接着120多个电子控制单元(ECU)。此外,连接软件组件的内部信号的数量要比外部信号的数量大两个数量级。软件架构设计中的一个重要任务是,架构组件应该以有序的方式很好地彼此隔离,创建具有合理层次结构和相对独立的系统隔间。这对于今后在现有功能的基础上开发新功能是至关重要的。另一个同样重要的任务是做出架构决策,支持维护诸如安全性、可靠性、高性能、可用性等属性。相较于权衡上述共存的两项任务,问题在于存在不同层面的架构考虑,例如从功能角度对ECU功能进行分配以及之间的交互,从需求层面保证相互之间合理配合,从软件设计角度保证软件组件设计以及组件间的交互,考虑不同层面的合集,已合理的方式处理是一个挑战。随着复杂性的挑战不断增加,已经有人提出了解决它的技术,例如AUTOSAR架构的推出,以及SOA。至少软件抽象级别上,AUTOSAR是简化复杂性的又一步。通过统一汽车领域的专业知识,可以为软件体系结构开发标准的关注点分离,使基本软件、运行时环境和自适应服务分离。相对于AUTOSAR,面向服务的体系结构(SOA)在降低复杂性方面相对成功。它统一了功能和设计,同时划分了服务。然而,SOA的一个关键挑战是,服务本身可以是复杂的结构,由许多其他服务组成。这可能会在服务设计之间创建依赖关系,从而违背SOA原则。另一个关键的挑战是,某些服务对实时性要求很高,需要由基本的软件流程进行优先级排序。在现代汽车中,这样的服务非常多,很难采用彻底的SOA。在软件架构的研究中,需要对这两个挑战进行适当的审查。但这两个挑战似乎受到两种权衡的限制,第一种是重用和复杂性之间的权衡,第二种是性能和复杂性之间的权衡。到目前为止,前进的道路似乎还很模糊。在这种情况下,目前尚不清楚如何区分偶发复杂性,因为这样的区别取决于产品的特性:例如,根据性能要求,某些服务可能需要在中央ECU,或根据可重用性需求,某些服务得到耦合(变得更复杂)。要为性能或可重用性牺牲多少解耦是很难量化的。软件变体引入了复杂性的第三个主要维度。值得注意的是,为了根据不同的地形、温度、海拔、排放法规、文化偏好等因素调整不同的参数,同一款软件有数百种不同的变体。变种车型为高端汽车制造商提供了最大的竞争优势之一,使他们能够满足不同市场部门的需求。但与此同时,它们也成为最具影响力的复杂性来源之一。变体不是软件的部件或工件,而是整个软件,其变量值和已编译代码集的范围略有不同。这意味着有一个软件超集产生了软件的多元世界,每一个都有稍微不同的属性。随着变量的出现,代码、体系结构、需求和测试的复杂性也随之增加。变量模糊代码与需求和测试的一致性。变种使软件符合ISO 26262和ASPICE,使持续集成成为一个半完整的范式。图1显示了一个大型ECU软件的变体伸缩示例。从商业角度来看,四个变化点分别是车型、发动机类型、排放区域和驱动类型。每个变更点都有几个业务变量。左边看上去很少的业务变体数量,在图的右边就变成了114个软件变体。至关重要的是,线性地添加业务变量,以指数方式增加软件变量。处理变种方面的一个进步是开发了软件产品线。管理软件产品线的方法无疑降低了软件的复杂性,因为它们有助于严格的计划和重用软件以满足不同的市场需求;否则,根据市场需求开发单独的软件开发分支会导致代码库成倍增大。但与此同时,这并不意味着软件的复杂性会变得像软件只有一种变体时那么小。事实上,越来越多的变体会触发创建更复杂的代码,不管产品线设计得有多好。一个棘手的事实是,增加的变体在软件中产生了本质上的复杂性,因为实现这些变体需要一定数量的软件。特斯拉(Tesla)和苹果(Apple)就是对变种车型采取激进做法。减少变量以获得更好的质量和开发灵活性。汽车软件的安全性、可靠性和性能至关重要,在实现之前需要进行严格的功能设计。这种设计最初是在系统设计者的细致讨论中产生的,以自然语言文本和图表为代表。这些是软件需求说明。与源代码一样,软件需求也趋向于变得复杂。复杂的条件和状态机是复杂性的典型来源。其余的复杂性是偶然产生的,这是由于语言使用不当造成的。为了降低复杂性,可采用编写简单需求的标准化模式,采用降低复杂性的语言结构等。改进这些技术的一个关键挑战是,自然语言的形态非常丰富,这阻碍了为开发简单需求创建清晰的规则集。当这个挑战被解决的时候,在需求的整体中存在一个更有问题的挑战。经统计,整个沃尔沃软件超集的功能需求超过10万项。功能需求被进一步分解成多倍的设计需求。如此巨大数量的需求应该持续地与源代码和测试保持一致,以保持可追溯性。否则,对于即将到来的缺陷和变更请求,正确地处理各自的源文件和测试[20]会变得令人生畏。如果缺陷在生产几年后出现,这是特别具有挑战性的。当源代码经历变更时,相应的需求错过了这个更新,知识的不协调就产生了,这使软件从业者感到困惑。为了使这个问题更加复杂,对于每一个源函数变量都必须有一个对应的需求变量。虽然源代码变量可以由代码内部的预处理器处理,需求变量也可以由需求管理系统处理,但棘手的问题是,如何维护源功能变量和需求变量之间的可追溯性。
尽管复杂性在这四个领域中表现为不同的形式,并且需要不同的测量方法,但在所有领域中都需要清楚地区分本质复杂性和偶然复杂性。在某些情况下,这种区别似乎更加明显;例如,应该消除未使用的变量,或者重构深度嵌套的代码。在其他情况下,这种区别更像是一个优化问题;例如,理解性能和模块化之间的最佳权衡。此外,还存在工具问题,会带来意外的复杂性;例如,将代码和需求分离开发为一个系统。如果汽车公司渴望开发越来越复杂的汽车,并保持目前的发展速度,他们应该对研究社区更加开放,对承诺的复杂性管理研究更加重要。另一方面,研究界应该做出更认真的尝试,创造出能够真正帮助实践者有条不紊地降低复杂性的方法。