先看边界,再看细节
这些年做项目,陆陆续续也接触过不少不同的控制器。有些比较熟,有些也完全是第一次碰。熟悉的早已轻车熟路,不熟悉的,我居然也经常能猜个八九不离十。
莫非是我有什么天赋?
后来我才发现,好像也没那么玄乎。只是这些年做项目,慢慢养成了一个工作原则:先看边界,再看细节。
所以,每当碰到一个自己不太熟悉的控制器,我通常不会急着先去啃那份厚厚的SOR,也不会马上去逐条研究需求。
倒不是因为这些东西不重要。
只是刚接触一个新产品的时候,就直接一头扎进几百上千条需求里,会让我觉得有点发懵。
SOR 里的每个字好像都认识,每一条单独拿一条出来,又似乎也都能理解。但这个功能为什么要做,它和其他功能是什么关系,它又处在整个控制器的什么位置……
当这些东西一下子全摊开在你眼前时,反而很难能建立感觉。
因此,我通常会先去看两样自己更熟悉的东西:Pin 和 CAN,也就是硬件接口图和通讯矩阵。
当然,通讯接口不只有 CAN,实际项目里还会碰到 LIN、以太网之类的东西,这里先不展开。
以前也没认真想过为什么,反正每次基本都是这么干。现在回头看,其实我最先想搞清楚的就一件事:
这个控制器从外面接收什么,又往外面输出什么。
先说 Pin。
看一个控制器的 Pin,基本就能知道它直接连了哪些东西。供电、地、唤醒、传感器、执行器,还有各种硬线输入输出。
这些东西看完以后,这个控制器大概在干什么,心里其实已经有点数了。
它需要采集哪些传感器,要控制哪些执行器,哪些地方需要底层软件额外配置,哪些功能需要集成相应的应用层组件。
之后再和现有的基础软件做一下对比,大概也就能看出,这个项目需要新增或者修改哪些东西。
然后就是 CAN。
CAN 要比 Pin 复杂得多。一份 CAN 矩阵里,往往有几百个信号。如果一上来就从第一条看到最后一条,很容易越看越乱。
所以,我一般会把发送和接收分开来看。
发送信号比较直接。既然规定这个控制器要发,那软件最终肯定要把这些信号都做出来。看看它要往外发什么,其实也能反过来帮助理解这个控制器要完成哪些事情。
接收信号要复杂一些。
有些关键信号会直接影响系统功能,有的只需要 mapping 转发,还有一些虽然收进来了,但当前软件并不会去使用。所以我一般会优先看那些真正参与功能的信号。
如果我对当前控制器不太熟悉,就还会去找一些类似项目的 CAN 开发文档。不同项目、不同客户之间肯定会有差异。
但同一类控制器,很多基本的处理思路还是有参考价值的。看看以前哪些信号会重点处理,再回来评估当前项目的矩阵,通常会快很多。
有时候 Pin 和 CAN 看完,还没正式开始逐条看需求,我心里大概就已经有数了。它接了什么传感器,控制了什么执行器,又在和哪些控制器交换信息。把这些东西拼起来以后,脑子里慢慢就有了一张画面。
这时候再回去看 SOR 和需求,感觉就完全不一样了。原来散着的一条条需求,开始能找到自己的位置。
而且先看边界,对后面的开发还有一个很现实的好处。
如果连最基本的输入输出都没搞清楚,软件上车后可能连正常运行都做不到。该采的信号没采进来,该驱动的东西没驱动,该收的 CAN 没收,该发的 CAN 没发。车都动不了,后面的功能、标定、测试也就无从谈起。
所以我更希望第一版软件先正常跑起来。它可以不完美,也可以没满足全部需求,但至少能通信、能运行、能驱动、能调试。
一个能运行的软件,是后续完善的前提。
这也是为什么在项目早期,我非常反感把太多精力放在那些 nice to have 的功能上。开发资源有限,先解决“能不能跑”,再慢慢解决“跑得好不好”。
现在回头看,我为什么总是先看边界,大概也就说得通了。
边界先确定下来,后面的需求也就有了位置。增加需求也好,修改逻辑也罢,基本都还是围绕着已有的输入和输出展开。
如果一个需求真的超出了现有边界,比如需要新增传感器、执行器或者外部信息,那改变的可能就不只是软件逻辑了,而是原来的边界本身。
所以对我来说,先看边界并不是为了少看需求。
而是先搞清楚:
这个控制器手里到底有什么,它又能影响什么。
边界看清楚了,后面的事情,也就有了着落。