一个合格的平台化组件应该是什么样的(linux C语言)

1. 为什么要开发平台化组件

  • 项目或者业务越来越复杂的情况下,组件化开发更适合快速迭代,在添加修改组件时候不需担心影响其他组件
  • 解决业务模块划分不清晰,耦合度大,较难维护
  • 可单独开发,测试,发布一个组件,不需要像以前一样开发完某个功能,就需要编译、运行、打包整个项目
  • 某个组件出现问题,可直接对组件进行处理,不必担心会因为修改而影响到整个工程
  • 组件划分后,组件的开发不受其他业务影响,可以多个组件并行开发,加快开发进度
  • 组件可以很好的提升代码的可重用性(而非可复制性),如果有其他项目需要该组件可以直接引入使用,而不是拷贝代码,拷贝资源等
  • 组件单独测试方便,测试完成后进行集中测试,如果后期有修改组件,只要组件提供的能力或者接口不发生改变,就不需要再次进行集中测试,减少测试工作量
  • 如果有新人的加入,可以直接分配组件进行开发,而非需要熟悉整个项目,可以从一个组件的开发使新进人员比较快速熟悉项目、了解到开发规范
  • 组件中包含有基础组件,这些组件也算是技术的一种积累,为未来开发新项目提供更快速的响应
  • 可以更早下班

组件化就是将一个产品拆分成一个个小的功能模块,每个功能模块完成属于自己这部分独立的功能,使得整个项目的管理和维护变得非常容易。
保证代码在高质量完成需求的同时具备良好的可读性、可维护性。

2. 平台化组件是什么

2.1 平台化组件的定义
  • 一个包含源代码、说明文档、demo、成果物自动输出脚本的代码目录
  • 一个源代码为高内聚低耦合的代码集合
  • 一个源代码至少包含组件初始化组件销毁组件运行组件回调函数注册四大接口的框架
  • 一个可适用于多个嵌入式平台的组件
2.2 定义说明
  • 高内聚低耦合:demo可单独运行在嵌入式平台
  • 上述四大接口需要在对外提供的头文件中体现
  • 组件初始化:分配组件运行需要的空间与资源,如存放回调函数结构体的内存,初始化锁、信号量等
  • 注册回调函数:组件与外部调用者之间的协议数据交互、日志回调函数注册
  • 组件运行:数据收发、流程处理
  • 销毁组件:释放组件相关资源

3. 如何做好平台化

3.1 合理的开发目录
Component_name          //平台化组件名称
├── Makefile            //打包生成库
├── README.md           //简要说明组件用途
├── demo                //演示组件库接口使用
│   ├── Makefile
│   └── src
├── docs                //存放组件相关文档
│   ├── 使用说明.html
│   ├── 使用说明.md
│   ├── 概要设计.doc
│   └── 详细设计.doc
├── include             //组件需要依赖的头文件
├── lib                 //组件需要依赖的库
├── src                 //组件源代码
├── test                //单元测试代码
├── third_party         //组件需要依赖的第三方源码
├── tools               //组件相关的工具,如脚本
└── output              //组件输出成果物
       └── gcc-arm-none-xxx                //交叉编译链
           └── Component_name              //组件名称
               ├── include                 //对外提供头文件
               │   └── Component_name
               │       └── Component_name.h
               └── lib                     //对外提供封装库
                   └── libComponent_name.a
3.2 框架必要结构
  • 大多数情况下,至少包含组件初始化组件销毁组件运行组件回调函数注册四大接口的框架
  • 开源框架参考:https://github.com/jobbole/awesome-c-cn#frameworks
3.3 开发&维护流程
  • 开发流程
确认需求
编写原理文档
建立平台化组件开发目录
确定代码主要框架
编写确定对外提供头文件
编写单元测试代码
编写demo代码
开发组件代码
单元测试和demo验证
  • 维护流程
邮件发布组件
源码or库+头文件
使用文档
协助第一次集成,接收各产品线反馈
调整组件,更新文档
单元测试和demo验证
3.4 组件更新日志类型
  • [ADD]新增
  • [OPT]优化
  • [CHG]修复
  • [DEL]移除
3.5 平台化组件代码基本规则

代码中,如果不符合以下原则,必须特别说明。
以下规则的目的是为了降低开发中犯错的概率,仅供参考

  • 变量定义时必须赋初值
  • 较大的内存要从堆上分配,不能从栈上分配
  • switch语句必须有default选项
  • switch语句中,每个case必须加break(多个case有相同处理流程除外)
  • if语句必须有else项,如果if语句内含有不会依次向下执行的语句除外(return,break,continue)
  • if语句中,变量与0做比较
    • 布尔:if(flag), if(!flag)
    • 整型:if(0 == value), if(0 != value)
    • 指针:if(NULL == ptr), if(NULL != ptr)
    • 浮点:const float EPSINON = 0.00001; if ((x >= - EPSINON) && (x <= EPSINON)
  • 遇到if/else/return的组合,应该写为 return (condition? x:y);
  • 不要用return语句返回指向“栈内存”的指针
  • 定义一个结构体必须要对齐(提高内存空间利用率,在内存共享的情况下防止数据错位)
    https://blog.csdn.net/TAlice/article/details/82016508?spm=1001.2014.3001.5501
  • 不允许使用全局变量,但可以使用静态全局变量(防止增大代码耦合度)
  • 只在当前C文件内调用的函数,定义时必须加上static关键字
  • 循环操作里要有超时机制
  • 禁止对指针求sizeof,这样做有可能会将指针的长度视为指针所指向地址的长度,导致犯错
  • 函数入参必须检查其合法性
  • 添加必要的注释,但没有注释比错误的注释好(保证必要的注释的正确性)
  • 代码的编写要简单易懂,同时要考虑到后期的低成本维护
  • C语言写的代码,声明时需加宏限制
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #ifdef __cplusplus
    }
    #endif
    
3.6 平台化组件代码必要注释信息
  • 文件头版权信息

/*********************************************************************************
 *      Copyright:  (C) 2018 Wang Tao
 *                  All rights reserved.
 *
 *       Filename:  thread.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(2018年05月15日)
 *         Author:  wang tao <TAlicer@163.com>
 *      ChangeLog:  1, Release initial version on "2018年05月15日 00时34分04秒"
 *                 
 ********************************************************************************/
  • 函数说明信息
/** @brief Example function for orange project 
 *  
 * Example text 
 * 
 * @param[in] param1    description for param1
 * @param[out] param2    description for param2
 * @return none
 */
3.7 平台化组件版本说明

软件和说明文档版本A.B.C这些数字分别代表什么意思
以Spark1.6.0为例子来说明。

- 第一个数字:1
major version : 代表大版本更新,一般都会有一些 api 的变化,以及大的优化或是一些结构的改变;
- 第二个数字:6
minor version : 代表小版本更新,一般会新加 api,或者是对当前的 api 就行优化,或者是其他内容的更新,比如说 WEB UI 的更新等等;
- 第三个数字:0
Patch version,代表修复当前小版本存在的一些 bug,基本不会有任何 api 的改变和功能更新;
4.8 自动化处理脚本工具
  • 当前工具能自动生成平台化组件目录、必要基础文档框架、基础Makefile框架,链接
  • 使用方法:
wangtao@DESKTOP-1D526UH:~/Demo$ ./cmptTool.sh
Please input Component_name:test_component
Please input Author_name:wangtao
Successfully generated test_component

4. 几个思考

  • 需求与代码哪个重要?

    • 并不是所有的产品都能提出合理的需求,当你面对一个提出不合理需求的产品的时候,你需要坚持自己的原则,不能妥协。
  • 什么是测试驱动代码?

    • 测试驱动代码,你写的代码要可以执行单元测试。如果你发现你的代码很难写单元测试,那么你就要思考你的代码是不是已经不整洁了,或者说已经乱成一团了。
  • 什么是简单的代码?

    • 能通过所有测试
    • 如果某段代码在程序设计中反复出现,就证明想法在代码中没有很好的体现出来。总之,不要重复代码,只做一件事,小规模抽象。
  • 平台化组件向外(各产品线)提供成果物的形式(库or源码)

    • 不做平台化:前期快、中期慢、后期更慢
    • 提供成果物的形式-源码:前期慢、中期快、后期慢
    • 提供成果物的形式-库:前期慢、中期快、后期更快

    那我们到底要如何抉择:

    • 无论哪一种,都应该以开发一个库的标准去要求自己,这样才能保证代码的高内聚与高度模块化
    • 建议先以源码的形式提供平台化组件,等功能稳定、对外接口固定后再以库+头文件的形式提供平台化组件
  • 单元测试在实际过程中存在的问题(以下观点来自某大佬)
    作为C程序员,为什么我们在工作过程中很少被要求做单元测试,以至于工作一两年之后甚至都没听说过单元测试,但是大多数开源项目都是有做单元测试的?我认为有以下几点原因:

    • C程序员大部分都是做嵌入式工程师,偏底层,多多少少都和硬件沾边,以至于弱化了软件设计;
    • 嵌入式岗位的产品大多数做是靠实体产品挣钱,不是靠软件服务,普遍不注重软件维护;
    • 单元测试也是写代码,也会占用工作时间,上班的都知道,工作是做不完的,所以不愿意去写单元测试;
    • 公司决策,公司、部门专注于产品快速迭代,以完成软件功能为首要,反正有专门的测试团队,要求程序员快速完成功能,却不对代码质量做把控;
    • 开源项目不一样,开源项目可能会被每个程序员查看,代码写得太差,可没关注量,个人、团体、公司的形象就上不去;
    • 开源项目一般都会持续迭代,使用单元测试优势特别明显,能快速迭代,快速测试;而且开源项目由于其特性,以至于每个人都可以使用简单的环境进行测试,如果使用人工测试的方法就很难满足;
    • 开源项目使用的技术理念相对比公司内更激进,接纳意愿更高,大环境也更容易满足。

    那我们到底要如何抉择:

    • 写良好的软件,我认为应该是每个程序员的基本专业、职业素养,要有这样的心态去写代码;
    • 如果你的公司、部门要求做单元测试,我觉得这是幸运的;
    • 如果公司没要求,你可以提建议,谈谈单元测试的优势,要是有不可逆因素拒绝了你的提议,那你可以在开发之余为你的代码编写单元测试;
    • 如果你是在做开源项目,应该没有太多说的,懂的都懂。
      从cmockery入门C语言单元测试

5. 结尾

不知不觉,毕业已经快三年了,见过很多很好的代码,也见过不少的烂代码。最后我几乎绝望的发现,无论是谁写的代码,只要经过时间的洗礼,都会变成一堆屎山。我们就像不断重复把一块巨石推上山顶的西西弗斯,而我们唯一能做的,就是向好代码学习,向烂代码反省。正如团长说的那样,“一尘不染的事情是没有的,我们每天都在吸进灰尘,但不妨碍把事情做得好一点啊。”

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值