赞
踩
你一定不止一次的听说过模块化代码。
理想的模块化代码高内聚低耦合、逻辑清晰、经过严格测试,易于复用。
嵌入式 C 编程界到处流传着它的大名。在学校、在公司、在各种技术书籍中,你总能找到它的身影。
它被描述的像是无所不能,仿佛只要使用了模块化代码,你就可以节省大把开发时间,项目就能化腐朽为神奇。
对公司而言,这极具诱惑力。
节省开发时间就可以快速推出新产品、及时实现新需求,这可以带来真金白银。
以至于有些人了解模块化代码的优点后,惊喜的发现找到了一个可以无视人员素质又节省开发时间的终极方法:强制所有开发人员使用模块化代码。
现实真的就是这样吗?
在现实世界中,好像哪里有点不对劲:
模块化推了几年总是不成功;
开发人员防备心很重(多次掉坑里),宁愿自己重复造轮子,也不愿用别人的模块
强制开发人员使用模块代码,阻力很大。人们怨气冲天,影响士气
这是怎么回事?
道理说起来简单,但只要实际操作起来,一线开发人员往往会直摇头:手中已有的所谓“模块”质量参差不齐、模块的开发者鱼龙混杂,很多模块别说出了问题找开发方负责维护,就是原作者是谁恐怕都找不到了。在这种情况下,谈论“强制使用模块代码”,简直就是天方夜谭,颇有几分“何不食肉糜”的傲慢。
说白了,很多已有的“模块化代码”不好用,以至于开发人员对此失去了信任。
我还记得这些“模块化代码”是怎么出现的:
相信这个过程不会只发生在我的身边。
所以这些披着“模块化”外衣的代码被强制使用,一线人员一次又一次被这些代码伤害过之后,人与人、人与公司之间,再难有信任。
信任
这东西,看不到摸不着,重要却很脆弱。信任可以简化协作,这会在各个方面节省时间。但是信任需要长时间才能建立,只要一瞬间就可以失去。
以至于后来发展到,提及模块化时,有些开发人员竟隐隐生出反感。
这是一个不好的趋势,因为模块化代码确实有用,它是被工程实践证实的一种优秀的编程策略。
假如我们有一些这样的模块化代码:
为了和烂大街的模块化代码区分开,我们称这些代码为合格的模块化代码,毫无疑问,使用合格的模块化代码,真的可以无往而不利,真的可以节省开发时间!使用的人越多,复用的越多,节省的时间也就越多!
比如写一套合格的 Modbus 协议栈模块需要 2 个月,然后其他人直接使用这个 Modbus 协议栈模块,可能只需要半天就可以实现 Modbus 通讯。所以我们不要再抱怨手中的模块化代码有多垃圾,我们应该将它们改进成合格的模块化代码,我们要产出合格的模块化代码!
那么什么样的代码才是合格的模块化代码呢?
让我们来看一下合格的模块化代码具有的特性。
模块化代码一般由 .c
和 .h
文件组成。
假如为菜单(menu)设计一个模块代码,模块一般包含 menu.c
、 menu.h
和 menu_cfg.h
这 3 个文件。
其中,menu.c
文件是模块的具体实现,menu.h
定义了模块的接口, menu_cfg.h
定义了默认配置和选项。
很多人不明白为什么要单独多出来一个 menu_cfg.h
文件,这个文件蕴含的思想很重要,对于需要更改配置或选项的模块代码,这个文件是必不可少的,后续将会提到。
合格的模块代码应该是只读的。如果不是只读的,使用者要把它修改成只读的。
这是合格的模块化代码非常重要的特性!
很多人对此不解或充满疑问,但我们经常使用这种只读的模块代码,比如 C 标准库。
我们信任 C 标准库,我们不会修改 C 标志库,甚至我们都没有 C 标准库的源代码,我们无需理解它是如何实现的,我们只关注如何使用。
除了 C 标准库,Keil MDK 有一个 Manage Run-Time Environment
组件,如果你使用过其中的模块代码,就能发现这个组件提供的模块代码都是只读的(当然用户配置文件除外):
将模块代码设置为只读属性,显然是深思熟虑后的结果。这明确的告诉使用者:不需要也不能修改模块代码。
不能修改代码???
要是我需要定制参数怎么办?要是你的代码有错误怎么办?
先暂且压一压心中的疑问,我们这样做是有充分理由的。
用户不需要修改模块代码
用户使用模块化代码的目的是为了复用,为了节省开发时间。用户渴望的是拿来即用、用了还不出错的模块代码,所以用户并不想修改模块代码,甚至如果一个模块需要用户去修改才能用,那么可能会吓跑这个用户。
用户不能修改模块代码
模块代码不是只给某个用户一个人用的。如果每个人都自由的修改模块代码,代码很快就会烂掉。
模块也会不断升级,对用户而言,升级就是替换掉模块文件。但如果用户更改了模块内容,一段时间后又升级了模块,那么之前的更改会随着文件的替换而消失掉,依赖更改的代码会出现故障。特别是修改的人已经不在这个项目组,而接手的人又不能了解所有情况时。不要给人挖坑。
那么,那些因为不能修改模块代码而产生的疑问该怎么解决呢?
以 菜单
模块为例。进入菜单后,如果长时间无任何操作,可自动退出菜单。那多长时间合适呢,不同的项目有不同的时间,这不要修改模块代码吗?
不需要。
对于定义良好的模块化代码,所有可配置项,他们的默认值定义在 module_cfg.h
文件中, module_cfg.h
文件是模块的一部分。用户需要修改的配置项,定义在 app_module_cfg.h
文件中,同时 module_cfg.h
文件中定义的对应默认值失效。 app_module_cfg.h
文件是用户自定义的头文件。
具体到 菜单
模块为例,menu_cfg.h
文件中会给出默认的 超时退出时间
,代码如下所示,这里超时退出时间是 30 秒。
#ifndef __menu_config_h__
#define __menu_config_h__
#include "app_menu_cfg.h" //包含用户自定义文件
/*菜单无操作延时自动退出时间*/
#if !defined MENU_DELAY_AUTO_EXIT_TIME
#define MENU_DELAY_AUTO_EXIT_TIME 30 //单位:秒
#endif
#endif
只要使用 菜单
模块,用户就必须提供 app_menu_cfg.h
文件。如果要更改 超时退出时间
,只需要在这个文件中重新定义宏 MENU_DELAY_AUTO_EXIT_TIME
,同时,menu_cfg.h
文件中的相关宏失效。代码如下所示,这里将超时时间修改为 45 秒。
#ifndef __app_menu_cfg_h_
#define __app_menu_cfg_h_
#define MENU_DELAY_AUTO_EXIT_TIME 45
#endif
这并不是什么新鲜事,ST 外设驱动库中的 stm32f10x_conf.h
、操作系统 FreeRTOS
中的 FreeRTOSConfig.h
文件、网络协议栈 lwIP
中的 lwipopts.h
文件,都是类似的用户参数配置文件。
那模块中缺少我需要的功能怎么办?(新的需求)
那模块中有错误怎么办?(修改错误)
这种情况下,我可以在模块中增加代码或者修改代码吗?
不可以。
正确的做法是将 BUG 或需求提交给模块维护者。
只有模块的维护者可以修改模块代码。不要图快捷而修改模块的任何代码!
模块维护者需要保证对模块化代码而言,除代码质量外,另一些生死攸关的特性:
模块维护者更了解全局情况,他可能会因为需求不合理而拒绝你的请求,也可能会因为追求更通用性而扩展你的需求。他要考虑的东西更多,不会局限在某一个项目应用上。他要保证代码修改后运行不出问题,绝对不能出现用户更新代码后,程序编译就失败了,运行就不正确了。
因此,从这方面来看,在公司层面推行模块化,这是一个系统工程。这里没有万能药水,也没有不劳而获,在享受模块化便利之前,必须要投入相应的资源:
靠某个领导的意愿推行不了模块化,靠拼凑而来的代码推行不了模块化,它需要公司全方位的投入。
此外,它还需要人,能写出合格模块化代码的人。
只读,不仅是合格模块化代码的重要特性,这还是一个可以量化的特性。
可量化
意味着可测量:是否达成指标可唯一确定。用户将模块代码设置为只读后,如果不能正常使用,那么这个模块代码就不具备只读特性,这是可以唯一确定的。
而合格模块化代码的其它特性,比如代码质量,则不具有可量化特性。满足什么样的指标才是好代码呢?没有精确的数据可以描述。我们简要说明一下这些特性:
代码简单直接,明显没有错误
高内聚,封装可以封装的一切,隐藏可以隐藏的一切,绝不暴露不该暴露的信息
低耦合,模块自成一体,尽一切可能减少依赖关系
谨慎的规划好接口,有一组严密、定义良好的 API
严格遵循一致性、向下兼容性
严格测试,先试用再推广,需要经历现场的考验
这些特性都是合格模块化代码的重要特性,然而它们也是所有麻烦的起点,这些特性不可量化,需要依赖特定的人。只有哪些长久苦思、有数年或数十年从业经验、经过无数尝试和错误经历的人才会真正明白、真正写出符合这些特性的代码。
编写模块化代码有技术门槛,这就是麻烦的原因。
编写出稳定可靠的生产代码已经很不容易,但编写合格的模块化代码要求更高,需要程序员站在更高的层次。
如果一个好苗子没有辜负大学四年,当他走出新手村走向社会时,可以认为他的技术水平达到了20级。这个好苗子进入公司,经过一年的实践锻炼,他升到了50级,可以在老员工指导下更改需求了;又过了三五年,好苗子成了技术骨干,他升到了100级,可以独自干项目了;又过了几年,好苗子成了小组长,他升到了200级,可以做系统架构了。那多少级可以写出合格的模块化代码?可能至少需要500级!
这意味着并非所有人都能写出合格的模块化代码。
这个结论多少有点让人沮丧,也多少会让那些一心降低人为因素影响的领导恼怒。但“并非所有人都能写出合格的模块化代码”并不代表“没有人能写出合格的模块化代码”,既然知道了模块化代码的好处,那就要努力编写出合格的模块化代码。
如果一个人有了努力编写合格模块化代码的决心,也有进益求精的态度,那么他需要什么知识来支撑自己呢?
这需要细心、谨慎、并不断的学习,多看、多想、多练。
一个不好的消息是,这个过程没有捷径,时间、经验、态度缺一样都不行。
好消息是网上有很多优秀的开源代码可以参考,可以从开源项目 EmbedSummary 中找到这些代码。
在编写模块化代码的过程中,必须时刻提醒自己,模块代码是很多同事工作的基础,代码必须精益求精!
读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃‘▽’〃)
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。