嵌入式软件架构师的“我”为作者本人
发表时间:2023-10-06 11:02:06
文章来源:炫佑科技
浏览次数:210
菏泽炫佑科技
嵌入式软件架构师的“我”为作者本人
大家好,今天我想分享一篇关于嵌入式软件架构师的文章。 文章中的“我”就是作者本人。 希望对从事嵌入式软件开发的您有所启发。
我从事嵌入式软件开发有六七年了,涵盖了bsp、驱动、应用软件、大厅等,除了关注嵌入式行业的发展之外,我也关注一些Web方面的技术,后端服务器、分布式等方向。
*近,我有了改变行业方向的想法。 我想做后端服务器相关的开发。 由于之前的工作并没有实际需要这个,所以只是关注了一下,学习了一些知识,比如:NIO、epoll、ngnix、、、Libuv、高并发、分布式、redis、、、、都比较复杂我对它们只了解一点点,但我并不是很老练。 令人意外的是,我屡次被互联网行业看不起,面试机会也很少。
这时候我就思考问题出在哪里。 有嵌入式背景的人就那么不受欢迎吗? 当年,嵌入式和驱动开发是蜂拥而至的行业(有点夸张,不过八九年前,嵌入式听起来比做java web还牛逼)
问题总是有原因的。 我解释一下我的理解:
1. 为什么没有嵌入式软件架构师?
打开各种招聘网站并搜索建筑师。 各种系统架构师、Web架构师、后端服务器架构师等都会出现,但很难看到嵌入式软件架构师。 嵌入式软件不需要架构吗?驱动程序不需要架构吗? 答案当然是,但是为什么这个领域没有职位呢?
我的看法:目前国内嵌入式开发主要分为嵌入式底层开发和嵌入式应用开发。 嵌入式底层开发一般称为驱动开发,或者bsp开发,有时也称为linux内核开发。 这个名字听起来很混乱。 一种非常优雅的感觉。
为什么没有建筑师拥有如此享有盛名的名字? Linux的架构师是Linus和其他Linux开发者和维护者,因为Linux或者操作系统本身就是一个解决常见问题的通用平台。 Linux开源领域的大佬们已经制定了架构规则,就没有什么可玩的了。 大部分工作只需要按照规则框架填写即可。
而且,目前国内大部分企业的业务需求只是针对外围设备、嵌入式平台的集成以及搭建剪裁。 业务需求不会超出所提供的功能范围。 因此,开发人员不需要设计和实现新的架构。
那么嵌入式bsp开发人员是做什么的:除了调试各种外设,擦硬件的屁股,解决一些稳定性bug(具体工作这里就不详细描述了,调试外设只是增加一些经验,增加广度,对深度提升没有多大贡献,只是沿着不会调试->能调试->更快调试的路线发展,解决稳定性问题确实需要一些经验积累)
至于嵌入式应用开发,业务逻辑一般比较简单,被很多人忽视,所以招聘人员会觉得没有必要找架构师级别的人。
至此,我觉得嵌入式行业不需要架构师,他们被互联网行业鄙视也就不足为奇了。
但事实真的是这样吗? 对于嵌入式底层的开发来说,国内有能力对驱动架构提出架构层优化的开发者应该不多,所以对于大多数普通人来说,*好还是不要“妄想”做Linux。 作为一名架构师(当然我相信中国人中一定有一些有这种能力的伟人),发现并解决一些bug是比较靠谱的。
2.我们真的不需要建筑吗?
我结合我自己的实际经验,给大家讲一个嵌入式设备应用软件的架构设计和优化。
我曾经接手过一个项目,采用的是单进程多线程的模型。 该项目包括几个模块,用a、b、c、d和e表示。 这个项目的业务逻辑决定了这些模块之间有很多联系。
例如:在*初的设计中,模块a是一个状态监控模块,它会根据监控到的状态调用模块b和c的接口来实现一些功能(多线程的好处是方便直接调用,所以大多数开发者都是这样做的,很简单(Rough),但是需求总是在变化的。 添加 f 模块。 f模块还需要处理a模块监控到的状态。 按照前面的套路,完成这个功能需要两步:
1、在模块f中提供接口;
2. 在模块a中调用该接口。 至此,新的需求已经“完美”解决。
前面说过,需求总是在变化的,新的需求又来了。 当客户提出定制需求时,需要再添加一个g模块,该模块也处理a模块监控的状态。 不过这个定制需求并不需要刚刚添加的f模块。 这时,*简单粗暴的方式就是定义一个宏来区分定制需求和之前的通用需求,构建两个程序版本。
这种做法看似简单,但如果后期定制需求逐渐增多,维护这么多定制版本的程序将是一场噩梦。 代码管理和通用性也会是一个大问题。 同时,代码中充满了不同宏定义的差异。 处理,
#ifdef xxx
do_something;
#endif
更好的做法是添加设备模型版本的动态监控,使用一个构建程序版本来动态支持所有定制需求,从而减少不同构建程序的维护。
但这种方式仅仅解决了构建程序的版本维护工作,并没有解决宏定义的差异化处理问题。 只是将之前的宏判断改为动态设备版本号判断。 如果这些差异化判断只集中在一个地方进行的话,不会造成大而复杂的问题,但显然这并不能保证。 有可能这些差异化处理会蔓延到整个项目的各个角落,让项目维护成为一场噩梦。 。
不需要先进的软件思维。 大多数人都会想到将差异化的部分提取出来,放到一个统一的地方进行集中管理。 对差异的修改只集中在这个统一管理的地方。
一般的做法是使用设置hook,然后在里面自定义差异化需求,配置差异化处理。
对应上面的例子,在a模块中添加一个hook,然后在系统初始化的时候,根据设备版本号区分定制处理函数。 同时,这些定制的处理功能应该放在同一个地方进行处理,否则仍然会分散在各个地方。 在角落里没有意义(前一种方式无法在不放置挂钩的情况下将这些差异化的配置放在一起)。
这种方式的另一个好处是,我们对功能需求的改变不会影响模块a的处理,即当我们添加功能时,不需要修改模块a的代码(前一种方法需要修改模块a的调用) ),从而实现模块的分离。
至此,第二种方案的架构(实际上是没有架构)相比**种方案已经提升了不少,至少让开发者轻松了一些。 对于其他的定制需求,开发者只需要修改这个即可处理,只需关注差异化部分即可。
软件需要不断发展。 第二个解是*优解吗? 当然不是。 还有优化空间吗?
我们先从一个话题开始,说说多线程/多进程模型的优缺点,主要是多进程的优点:
课本上的解释我就不提了。 首先,我推荐大型项目使用多进程模型,无论性能如何。 主要原因有:
模块解耦
很多开发者维护和开发的多线程模型项目都应该在一定程度上存在以下问题:模块之间直接调用。 如果你不相信,那么,你的项目必须被分成模块。 现在随机删除一个模块。 构建看看构建是否能够通过(只需构建而不需要运行)。 相信大多数情况下你都会遇到某个函数调用或者某个全局变量找不到的情况。 这种情况说明你的模块之间存在问题。 强耦合。
由于多线程的天然优势以及地址空间的相互可见性,直接调用非常容易。 很多经验很少的工程师很容易就可以写出简单粗暴的可以直接调用的接口。 如果遇到一个接口的功能,那就方便了。 我将其删除并直接使用。
这样,随着整个项目的功能不断添加,模块之间的交叉就会越来越多,耦合度也就越高。
我之所以推崇多进程,是因为多进程可以在物理上隔离这种“方便”的通信方式。 这样一来,当你想要实现一个模块交互的时候,你就会更多地思考这个交互是否有必要。 如果有的话,我们会进一步考虑接口定义是否简单清晰(因为进程间通信比较麻烦,开发者会仔细考虑接口和协议的定义,以减少交互,明确接口,否则就会),就像生活一样,如果事情一直进展顺利,人们可能不会想太多或想太多,但如果路上有一些坎坷,他们就会有另一种理解。
所以我的想法是,多进程模型会迫使你更多地思考程序设计,物理上减少模块的耦合。
抽象公共组件,分离公共功能和业务逻辑功能:在将多线程模型修改为多流程模型时,经常会发现一些接口代码在多个流程模块中重复出现,因为接口功能之前在一个流程模块中。进程空间可以被大家直接调用。 例如,接口A被模块a和b调用。 模块a和b分离为两个独立的进程后,需要分别在a和b中实现接口A。 无需解释,代码重复。 这是软件工程中的禁忌,必须消除。
方法也很简单。 将这些多个模块调用的接口分离处理成一个lib,供其他模块调用。 当你完成这部分工作时,你发现了什么? 剥离出来的接口是否可以作为整个项目的公共资源? 该组件存在。 完美情况下,lib下的代码是通用的基础组件,每个模块都是独立的业务处理模块。
方便定位问题
在多线程模型中软件开发,当一个线程异常退出时,会导致整个进程退出。 当然,通过一些crash信息,可以定位是哪个线程死掉了。 但是,如果这些线程模块是由多个小组和人员维护的,当整个进程崩溃时,*后如何确定应该由哪个小组来解决将是一个很大的问题,而且有时一个线程挂掉的现象实际上是另一个线程造成的模块(耦合的诅咒)。 在这种情况下,群体之间难免会出现争论和推诿。 (自信的工程师认为我的代码没有任何问题)
而如果你使用多进程模型,那么,你的服务进程挂了,你可以自己找原因,没什么好争论的。
方便的性能测试
多线程中单个线程的资源占用情况不容易检查(至少有的嵌入式系统没有完整的命令)。 当整个进程的资源消耗非常高时,如何确定使用哪个模块线程进行定位就和3一样难以决定,而且如果是多进程模型,则检查谁的进程占用资源多。
其实这还是一个粒度的问题。 如果同一个系统被划分为多个进程,单个进程的复杂度一定比只有一个进程的复杂度低很多。 降低的复杂性使得更容易定位和发现各种问题。
分布式部署
互联网行业一直强调分布式、云等,但嵌入式行业却很难。 看似不需要分布式,其实是对的。 大多数情况下,嵌入式使用单芯片,独立运行,并且是分布式的。 遇到的人很少。 但如果那天你在一个设备中,将原本由一颗芯片完成的功能分散到两颗芯片上,那么多进程的扩展就会容易得多。
这只是一个特殊的例子。 其实嵌入式设备是一个分布式的行业,只不过从一开始就已经是割裂的,而不是从集中式走向分布式的路线发展。
方便公司的代码权限隔离:我其实很鄙视这种做法。 公司必须信任其员工,但诚信在中国已经是一个问题。 。 。 。 ,做一些隔离是可以理解的。
在多线程模型下,如前所述,如果删除一个模块,则可能无法构建。 您需要将所有代码公开给所有工程师吗? 显然不是,所以各个模块只能以库的形式提供,但我觉得把通用的功能接口组织成通用库是正常的做法,如果业务相关的模块也以库的形式提供会好一点。 。 。 。
在此,我想补充一点,以上所有优点其实都不是很关键。 它们不允许多进程相对于多线程模型具有绝对的优势。 只是从个人角度来看,多进程模型能够倒逼工程师去思考和解决一些问题。 问题。 (无论什么型号,有经验的工程师都会思考这些问题)
上面说了这么多,是时候考虑把之前项目的例子改成多进程模型了,不然就只是纸上谈兵了。 开始吧:
**个问题是:选择多进程通信方式。 多线程之间不能直接调用。 那么如何选择多进程通信方式呢?
Linux下可用的IPC方法有很多,这里就不一一列举了。 对于非大数据量的控制和通信消息的传输,更好的方法是在本机上使用Unix方法。 (这种方式有什么好处??当需要把单一系统变成分布式系统时,优势就变得明显了)
但仅仅用它来实现上一个例子的功能也会存在一些问题:
还是用前面的例子,我先说明一下,我们优化的第二种方案不能再用在多进程模型中了。 原因比较简单,应该不用解释了……
简单的做法是在方案一的基础上改为直接调用通信(只需定义通信协议即可),但是熟悉开发的工程师都知道,在开始通信之前,必须先做一些前期工作(主要是连接,关联两个模块) up),所以前面的例子就会变成这样。 模块a需要与模块b和c建立连接。 如果添加模块f,则模块a也需要与模块f建立连接。
在这种情况下,如果你在脑海中画出一个连接图,你会发现我们编织了一张蜘蛛网,节点之间的关系错综复杂。 和**个选项一样,如果我们添加一个与a关联的模块,我们必须修改模块a的代码。 ,而且这种情况比多线程模型要繁琐复杂得多。 这种方法绝对是一场噩梦。
怎么解决呢,我想很多人肯定都想到了利用总线分发。 了解系统开发的人会想到它,了解它的人会想到ubus,了解桌面的人会想到dbus,互联网行业的开发人员也一定知道redis中提供的sub/pub模块。
以上,ubus等原理很简单,就是建立消息中心,构建转发路由模型。 所有其他模块之间并不直接交互,而是通过消息中心进行转发和路由。 如何确定路由规则,订阅/发布是使用观察者模式来定义规则的。
嵌入式开发或者C语言开发人员常常错误地认为设计模式与面向对象语言有关,并且是面向对象语言所特有的。 虽然很多专家都对这方面进行了普及,但考虑到一些开发者的信息渠道比较封闭,所以这种想法还是很受欢迎的。
基于这个模型,我们上面例子的需求可以通过添加消息中心模块来轻松解决。 所有需要通信的模块只需要连接到消息中心模块,然后订阅自己感兴趣的事件,当事件发生时,只需要进行相应的处理即可。
这样,上面的模块b和c就订阅了模块a的事件。 当模块a检测到事件时,它会发布该事件。 事件首先到达消息中心,然后消息中心将其转发给模块b和c。 对于新添加的模块f,只需要订阅该模块即可,不需要修改模块a的代码,功能扩展非常方便。
同时嵌入式软件架构师的“我”为作者本人,上面提到的定制开发也得到了简化。 如果定制版本需要添加模块g,则只需在定制版本中将模块g作为独立进程启动,然后订阅模块a的事件即可。 而定制版本与通用版本的区别在于是否启动模块g的进程,从而达到软件工程的一个目标:
添加功能就像搭积木一样。 您只需插入(激活)或拔出(禁用)模块即可。 功能变更仅限于一个或几个模块,不会对主框架产生任何影响。
以上大致描述了一个项目需求逐步优化的过程。 该示例似乎基于嵌入式项目,但它似乎也适用于软件工程。
3、来到互联网行业
查看各大网站架构师分享的关于本网站技术架构变化的文章。 首先提到的通常是根据业务将以前的应用服务器的功能进行拆分,并使其更加细化(例如电子商务的登录、注册、交易、产品和卖家等业务服务的拆分),然后进行部署将服务拆分到多个服务器上以提供并发性。
这听起来很熟悉吗? 是不是类似于前面提到的从多线程到多进程的划分?
分手后我们也遇到了沟通问题。 这时候很多消息中间件就应运而生,比如阿里巴巴的duboo。 我们简单了解一下这些中间件的原理。 无非就是订阅发布、RPC等机制。 可以说它们是相似的,但难点在于协议的制定和性能处理的改进。
对比互联网行业的负载均衡解决方案,似乎负载均衡前端也像一个消息中心。
上面说了这么多,我只是想说明一个问题。 软件的设计是相似的并且基于相同的思想。 虽然嵌入式行业的业务逻辑比较简单,但事实上,经过深思熟虑,还是存在很多架构上的问题。 改进, 设计.
但令我悲哀的是,一些嵌入式开发者鉴于业务逻辑的简单性,觉得用一些不太好的处理方法就可以解决问题,而不去思考如何优化和改进。 比如上面例子的**个例子,如果定制需求不多,维护不会有太大问题。 即使有很多定制需求,也可以通过招募一些初级程序员来维护。 每个人负责一组代码。 项目公司不存在。
同样,互联网行业和嵌入式行业也不应该存在难以逾越的高墙。 我们更应该关注的是通用的软件工程思维。
结尾
# 如何为电子工程师的私人工作报价
#我做了一份私人工作,但我没有时间去做。 谁想拿走它?
#抱怨工作中遇到的不好的事情
#请电路高手帮忙,如何更改电路?
#久久电子小小妹
莫玉群电子工程师
炫佑科技专注互联网开发小程序开发-app开发-软件开发-网站制作等