软件架构这东西,众说纷纭,各有观点。在我看来,软件架构是软件系统的基本结构,包含其组件、组件之间的关系、组件设计与演进的规则,以及体现这些规则的基础设施。软件架构,从来不是一件容易事,它贯穿在产品的整个生命周期,需要所有团队成员遵守并自律,才能将架构思想在软件中体现。新手工程师,由于经历的项目太少,看不到项目全貌,很难从全局理解软件架构。但软件架构真的只是资深工程师的专利吗?这个也不见得。古人作文,讲究立意为先。今天工程师做项目和产品,也应该先立意。这个意,就是指要有高度。工程师入门能从软件架构的高度出发,看待软件问题,相信对软件的理解,会更加深刻一些。因此,我总结了软件架构的六个步骤,供嵌入式工程师参考。
隔离硬件相关代码,建立抽象层建立统一的软件基础设施妥善识别和管理系统数据功能分层与分解组件及其接口设计测试、调试与跨平台开发的支持
今天,们将探讨设计嵌入式软件架构的第三步:妥善识别和处理产品数据。当工作过程中,我发现嵌入式工程师们,在思考架构问题,有两种倾向:
首先,思考问题的出发点,大部分都是硬件。嵌入式工程师们总是会倾向于,把整个嵌入式程序,搞成一个时刻在与硬件交互的底层代码,没有有效隔离硬件,更没有合理分层,甚至一竿子从应用层捅到寄存器。在《嵌入式软件架构的六个步骤(一)抽象层》中,我们对这一现象做过解释。这种做法,是由大部分嵌入式工程师的知识结构偏硬件决定的,可以理解,但绝不提倡。因为这种写法,不符合软件发展的主流趋势,不符合层次化和复用性原则,无法支撑大规模的嵌入式软件开发。目前嵌入式开发产品的软件规模大了很多,硬件有关的部分所占的比例,已经降到了非常小的份额。在大多数嵌入式系统中,真正的价值在于应用层代码,即与硬件无关的部分。
一竿子捅到底的架构
其次,工程师总是喜欢围绕中断、任务、总线的原始数据等底层资源,展开对架构的思考。这依然是面向硬件和面向底层的思维。在硬件资源紧张的年代里(15年前),任务的数量是有限制的(uC/OS-II只支持64个任务,而当前大多支持无限任务,只要RAM和ROM允许),而RAM也是非常紧张的,那时候的工程师,不得不将大量的精力,放在底层上,以便以最小的资源进行数据的处理。而现在,当资源变得不那么稀缺甚至有些过剩时,我们要面向业务逻辑进行数据结构的设计。而业务逻辑体现到软件里,本质上就是数据抽象与数据结构的设计,其次才是程序的编写。
一旦团队完成了软件架构的第一步和第二步,对硬件相关代码进行了剥离,并建立了统一的软件基础设施(非必须步骤),设计嵌入式软件架构的第三步就是妥善识别和处理产品数据。数据包含任何类型,只要是系统内部,又利用其功能执行的任何数据,包括一些中间数据和临时数据,都算系统数据。拿我曾经做过的机器人控制器举例,嵌入式系统可能具有以下系统数据:
IO口数据(含开关量输入口、开关量输出口、模拟量输入口、模拟量输入口)通信口数据(含串口、CAN接口、RS等)传感器实时数据电机实时数据车体状态数据地图数据任务数据指令数据当前线路数据当前位置数据错误与报警历史LOG数据配置参数脚本数据其他数据
这里面,有些数据,为一些功能独享,但也有很多的数据,由不同的器件产生,并被多个功能所共享。系统中数据越多,数据类型越多,数据共享越多时,系统架构就越复杂。当我们设计和构建一个实时嵌入式系统时,我们所做的核心是妥善识别和管理数据。
嵌入式软件设计的第一原则
数据决定设计,是现代嵌入式软件设计的第一原则。Linux的创始人LinusTorvalds在一次演讲中也曾经说过说:"烂程序员关心的是代码,好程序员关心的是数据结构和它们之间的关系。"他在谈到Git时,也曾表达过类似的观点,“好程序员和烂程序员之间的差别,就在于他们认为是代码更重要还是数据结构更重要。”我们上学时,就学过一个公式:程序=数据结构+算法。如果从嵌入式程序的宏观视角去理解这个公式:所谓的数据结构,就是数据结构与处理机制;而所谓的算法,就是代码逻辑。好的数据结构,总是会简化代码;而差的数据结构,会导致代码变的比较复杂。
我们可以创建各种漂亮的架构,去开发项目,完成产品。但最有效的架构是围绕系统数据设计的架构。一个只有10个数据和个数据的处理方式,是完全不同的。无论工程师琢磨出多么漂亮和优雅的软件架构,只要这个架构不是有效的支撑数据的处理,都是无助于实际开发的。
当我们专注于数据进行架构设计时,需要工程师对数据本身以及数据的转换进行高度