软件定义汽车(SDV)的概念被提出后,整个汽车行业,从OEM到Tier1、Tier2都加大了对于软件研发的投入(至少纸面上是如此)
而鄙人很幸运(或者说很不幸)正是汽车长长的生产链中的一颗螺丝钉,又很幸运(或者说很不幸)长时间从事汽车软件、
车联网、大数据等和SDV高度相关的工作,恰好亲历了整个汽车行业软件研发的变革。
"汽车就是四个轮子的智能手机,是下一代的移动终端"。广告如是说,专家如是说,收钱的公关和不收取的水军也是如是说,大领导如是说,小领导如是说,所以我也是对此深信不疑的,至少在每月领工资的时候是深信不疑的,而且我也发自内心地希望自己能够见证甚至参与新一代安卓或者IOS的诞生和成长。
尽管前景如此美好,但是大家也都承认(至少私下里是承认的),实现美好未来的路途还是充满艰辛的。荆棘丛生,诸如用户观念陈旧、数据隐私、信息安全、功能安全、境外敌对势力搞事情、生态不完善、算力和需求不匹配等等等等,但是这些都不是目前最最着急的(当然之后肯定会是)。
我作为一个长期混迹于底层(物理意义上的,不是软件意义上的)的工程师,而且有着技术栈的经历,且长时间处于第三方OB视角,我对这个问题有着最简单和最朴素的看法,当务之急,是要消灭汽车软件内全局变量。
什么是全局变量?
定义在函数内部的变量称为局部变量(Local Variable),它的作用域仅限于函数内部, 离开该函数后就是无效的。
在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序。
局部变量内存是分配在栈上,随着函数的调用动态的创建和销毁(随着函数栈帧一起)。而全局变量内存是分配在全局变量区,在编译时候已经创建并分配了内存(换言之,程序一运行,啥都没干,这部分内存已经被瓜分了)
汽车软件中如何使用全局变量?
在古板、刻薄、斤斤计较的传统IT行业内,全局变量是个很不受欢迎的存在,大部分编程规范都会告诉你除非万不得已,尽量少于全局变量。所以基本上只用于如下几个场景
- 存放不可变的常量(比如配置参数之类的参数)。这些常量一般在整个软件开发周期中这些常量基本上不会被修改,且广泛存在于代码中的多处。
- 对性能要求极致的场景(如何多个函数间标志位的处理和判断)。尽管是个人都知道,局部变量(作用域尽可能小) 函数 入参 返回值可以让你的代码更接近于艺术品,但是我们也要时刻牢记,传参和返回值都涉及到了内存之间的拷贝,这是有代价的,尽管当下大多数计算机不在意这九牛一毛的损耗,但是这个世界上仍然存在着一些极度敏感的场景。
- 某些逻辑借助于全局变量更好实现。尽管大部分用全局变量的场景都可以被更优雅的方式替代,但是不得不承认,在某些场景下,使用全局变量会使得代码简短且易于实现,尤其是那些开发中途才发现的问题或者半路才知晓的需求。但是在这种情况下,代码就引入了腐化的风险,不过,who care,老板收获了没有人会去看但是可以跑的烂代码,我收获了时间节省(相当于变相延寿了),简直是双赢典范。
而在于历史底蕴更加深厚,但是却有朝气蓬勃的软件行业,全局变量用来干什么那?
- 参数的配置
- 函数间参数的传递(有的工程甚至是全部函数传参都是通过全局变量)
- 获取别的函数执行的结果(有的工程甚至是全部函数结果的获取都是通过全局变量)
- 执行流程的控制(状态机),是的,你没有看错,"巧用"全局变量,甚至可以"简化"分支流程、循环流程。
为什么要这么用?
RTOS与XCP
在无耻的搅局者搞出那邪恶污秽的新一代汽车电子电气架构之前,汽车所有的软件都是跑在MCU中的,负责调度的也是一个简单的RTOS。得益于RTOS的优良特性,每次内存分配的地址都是相同的,所以在不修改代码的前提下,每一个变量都会有一个固定且全局唯一的内存地址。如果我们可以知晓这个映射关系,只要去读内存的数据,就可以任意获取这些变量了。同理,只要通过动态修改内存的方式,就可以任意改变软件的运行状态,运行方式。前者是汽车诊断的一部分,后者是汽车标定的一部分,而针对这些汽车行业内的常见需求,业内就有了XCP协议来专门干这个事情。
诊断和标定,单靠这个就可以养活很多公司,甚至一些做到极值的公司,可以摇身一变就成为业内技术大拿。而这一切全依赖于全局变量,只有广泛使用全局变量才能如此灵活而强大。
只是很遗憾,几乎(可能不用加"几乎"这个词)所有的现在操作系统都放弃了这个优良特性,导致那些采用MPU(行业内也有叫做A核、SOC的)的控制器,没有办法再如此使用了,除非每个进程都集成独立的内存读写程序。不过不用太担心,几乎所有从业人员都相信这个替代过程要持续好多年,至少主观上是如此。
开发工具、simulink、电动螺丝刀
和传统的IT软件亦或者是互联网服务、移动端应用不同,汽车行业的软件开发过程更加激进,这几年才开始有人热炒的低代码,在汽车行业内已经被广泛应用多年了。借助simulink等工具,一个汽车行业的软件工程师,可以不熟悉函数和指针,也可以没有听说过堆和栈,只需要简单理解数据类型,外加对业务逻辑(往往都是同步单线程的)的熟悉,就可以拖拉拽的方式实现汽车软件的开发。
而simulink生成的代码要简单的嵌套到框架代码中,成功编译和使用,需要明确新加的功能和已有框架的边界和接口,而全局变量就是实现这个的方法之一。
由于汽车软件行业的先进性,基本上没有人会在面试时候问工程师一些奇怪且无用的八股文:
- 什么多线程和锁那些为人所不齿的邪恶勾当
- 如何为了仨瓜俩枣的几个字节死扣堆和栈内存分配
- hashmap的加载因子为什么是0.75这类不明所以的问题
- 泄漏的内存垃圾是干垃圾还是可回收垃圾之类的无聊细节
- 对象是存在于堆上还是栈上,亦或者是自己家里
当然,这种先进性也是有一定代价的,喊着不要重复造轮子的人,往往不仅没有水平造出轮子,甚至都分不清轮子是三角形的还是正方形的(当然,本人觉得其实轮子实际上应该是一个不规则的类椭圆形)。老板抢走了我们的工具箱,给了我们一把电动螺丝刀,我们收获效率的同时,失去了快乐。
简单的应用场景
明确软件分层的边界,明确框架和应用的界限,却又可以将它们神奇地连接到一起,这一直是软件工程的关注重点。使用全局变量就是实现的方法之一,但是也不是唯一的方法,甚至不是最为广泛接受的方法。大部分程序员的门派都是采用函数实现的。
那为什么其它软件工程师非要这样标新立异,不是和汽车软件工程师一样采用全局变量,要知道全局变量是个简单好用的方式,任何人基本在第三节编程课就会想到这个方法,在第八节编程课前就肯定会熟练地掌握这个方法了。
其实答案很简单,相对而言,汽车软件中的变量更少更固定,整个软件运行过程中,没有太多的嵌套和调用。所以数据就比调用重要,全局变量就可以在不做出过多影响的前提下,做出更多花里胡哨的操作。
祖宗之法不可变
汽车软件主力玩家在过去相当长的时间内都是欧洲和美国,国内的玩家(旧势力)基本上都可以血缘追溯到他们,但是我却神奇地发现萨满文化才是这个行业的圭臬。对先祖之灵、远方自然神以及万物有灵的朴素崇拜是这个行业每个工程师的入门课程。
- 先祖之灵
- 亲爹或干爹,不言自明
- 远方自然神
- 看看那些竞争对手、供应商、花钱请水军吹牛的人、亲自吹牛的人,他们在做什么,你的方案为什么和别人不一样
- 万物有灵
- 除了我的同事之外,哪怕是没有毕业的实习生,谁都可以搞定眼前的问题
- 这部分功能网上应该有现成的代码,你找出来改改就行,为什么要说这么多我听不懂的理由做借口
在如此朴素的原则下,在一场场的仪式仪轨的熏陶下,大家分化成两类人:
- 甲: "先祖庇佑,祖宗之法不可变"
- 乙: "反正你掏钱了,东西又不是我的,你又没有付劝谏的钱,你说的都对"
在此思想指导下,前人用什么,就跟着用什么,根本就没有机会和能力去改变。
如此滥用全局变量有什么问题?
剑有双刃,事有得失。在有如此多优点的前提下,全局变量的滥用会导致一些微不足道地小问题。
- 各个模块的耦合性增强,不利于代码的复用和维护
- 没有办法很优雅的进行单元测试,只能交由人肉脚本去手动测试,好在汽车行业工程师便宜,这个问题也不大。
- 安全性很难保证,因为即使睿智如你,也没办法百分百避免你哪些睿智的同事悄咪咪地做出一些意想不到的修改,尤其是未来涉及并发问题后(如果有未来的话)
- 不利于服务的拆分,毕竟对于软件行业这样低门槛且想象力匮乏的行业,有人做出远程调用就已经要感慨庆幸了,更不能指望他们做出远程全局变量这种划时代里程碑意义的东西。
- 对内存造成浪费,当然对于汽车控制器硬件的高速发展而言,大概也许没有人会在乎这仨瓜俩枣
为什么这个问题不好解决?
祖宗之法不可变
代码维护了二十年了,二十年都过来了,修改起来谈何容易
很多人凭借祖传代码,从打工人熬成了监工人,现在你要谈颠覆,old money不允许
祖宗之法是有祖宗背书的,出了错也有先祖之灵担责,而现在你改了,成了是祖宗庇佑,败了则是你离经叛道。
不过雕虫小技
虽然我听不懂你们说的高内聚低耦合,但是我觉得这个东西不难,而且我们应该有类似的东西了
是在不行,我们还可以花钱去找供应商
新的东西可能也许是好的,但是它没有办法卖出更多的钱,反而要花钱
那些是我们不需要的
从业工程师都有一只莫名其妙的骄傲,可以归纳为三点
- 我们不需要
- 客户不需要
- 我们觉得客户不需要
没有钱
制造业利润薄,百分之十几的收益,没有办法大手大脚地花钱,比较要对股东负责。
研发要花钱,没有钱,就没有办法把破房子推倒重建,只能一层又一层,一年复一年地往上刷着白灰,并给哪些妄图指手画脚批评的人会以冷漠和犀利冰冷的眼神。
解决了这个问题,之后还有什么问题?
- 网络通讯 (尤其是让汽车工程师明白TCP和socket和can完全不同这件事,不能简单当成can plus)
- C语言 (C语言很底层,用起来很麻烦,它不是真理,更不是世界上唯一的光)
- RTOS (不能因为你用RTOS就认为这是唯一,至少竞争对手在改变)
- 单元测试 (尽管人不值钱,但其实也没有那么不值钱,上交同济的博士,其实可以做比测试更复杂一点的工作)
- IO与并发 (哎,这个真的不是大家想的那么简单)
- 数据 (数据归属权是存在质疑的,车厂也好,供应商也好,监管方也好,都有不同的想法,目前业内唯一可以达成的共识就是,尽管用户掏了钱,但是数据肯定是不属于用户的)
- 肉食者 (未能远谋啊,未能远谋啊)
软件的问题,真的只是软件问题吗?
你说呢?
国之大事,在祀与戎,前者是思想精神文明的建设,后者是物质文明的建设。软件定义汽车,恐怕也要从祀与戎开始处理问题吧。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。