软件从来不是一次就能完美的,需要以包容的眼光看待它的残缺。那问题究竟为何产生,如何去除呢?
1、软件问题从哪来?
软件缺陷问题千千万万,主要是需求、实现、和运行环境三方面。
1.1 需求描述偏差
客户角度的描述,在经过业务对接、产品经理的转述,最终呈现的软件需求可能已经偏离了原始的述求,开发人员基于自身经验的理解偏差,开发过程缺乏有效的沟通及监督,导致最终的软件功能与客户的核心诉求存在偏差。
1.2 异常处理机制不完善
嵌入式软件必定是运行在特定的硬件设备,硬件本身或环境问题等特殊干扰,开发人员因经验不足缺乏风险评估,面对电脑是无法全方位猜测、模拟各种异常环境下的差异,最终导致设备在特定场景下运行异常。
1.3 软件开发能力不足
嵌入式系统的复杂度与开发人员的能力矛盾,导致软件本身的逻辑存在缺陷。
2、软件开发与软件问题
关于软件bug的来源,排除不可控的外界因素,与软件开发人员相关,或者开发人员可以减少问题的发生的可能,从软件开发角度解决的方案如下:
2.1 重视需求分析
软件开发就是写程序,并设法使之运行,这是个错误的想法。软件结果与客户期望不一致,需求问题不全是软件开发的锅。大多数情况下客户的原始述求不会直接到软件开发,软件开发没法去反诉找客户确认,只能通过软件的实现形式去甄别不合理的,或者针对客观环境、研发团队的基础去评估风险。
比如客户要求可以设备可以定时1秒采集一次温度,精度要求0.0001摄氏度;或者要求数据采集持续采集24h后,每天12:00准点TCP上报后台服务器。这就需要考虑温度传感器的精度、RTC唤醒以及TCP联网时间、24小时采样数据的存储。如果硬件资源或者客观环境无法实现,盲目承诺客户,或者开始编码,最终结果可想而知。
软件开发是个人的任务,但开发前多沟通确认,进行风险评估反馈,减少开发的无用功,也是对开发人员的基本要求。
2.2 积累行业经验
嵌入式产品都是针对某个细分行业,见多识广,才能预判可能出现的异常,开发阶段有针对性的去处理,或者提前告知使用者去规避。有时候经验比技术能力重要。
2.3 提高开发水平
软件开发水平,首先是个人能力,熟悉软件SDK的应用,相关的操作系统、设计模式、调试方法等。软件开发能力大多数情况下决定软件质量和可维护性,这是个长期学习提高的过程,如果一定要提供捷径,那就是多阅读优秀的开源代码。
2.4 先设计再编码
软件开发不能随心所欲,先明确方案和大概的实现流程,胸有成竹,然后再开始编码,完善细节。这理论没毛病,但真正执行起来却比较难,大多数情况下都只在乎软件出结果,而实际上方案不合理,后期修修补补更浪费时间。如果制度和时间不允许,个人在纸上画画框图和结构,先构思再开发也能弥补,起码不至于南辕北辙。
2.5 编码规范
编码规范是软件开发团队合作的标准,嵌入式行业可以参考“华为技术C语言编程规范”,但实际开发过程,和前面的先设计再编码一样,各种不可控因素,比如项目进度压力和开发者水平与认知的差异,导致有编码规范却无法严格执行。随着软件工程规模的扩大,软件交期、代码同步、重构或交接,其风险也逐渐放大。存在编码规则并不能解决问题,只有强制执行才有意义。
2.6 代码缺陷静态检查与单元测试
软件质量是项目成败的关键点之一,在开发周期有限,人力资源不足的情况下,使用工具实现代码自动扫描,分析出潜在隐患点,可从源头减少软件bug,比如cppCheck、PC-lint等,实现代码自动静态分析,或者人工视检,有效规避简单的软件风险。
如果可能,最佳的选择是单元测试,单元测试比可交付成果本身更重要,文档注释不全时,单元测试就是设计文档;单元测试定义的API和用法,以及可能的使用风险点,就是最佳的参考范例;不足100%的覆盖率就是玩忽职守,开发人员应该全权负责测试自己造出的产品。依靠后期的黑盒测试发现问题,其消耗的人力物力,是编写单元测试的几倍,而且单元测试可以反复的自动测试。不过这种情况更多的是存在于开发理论中。
3、前期减少问题
软件问题的解决,有些不是个人能解决的,需要协调沟通,或者与研发团队的整体风格、制度有关。个人能决定的是软件具体逻辑,这也是体现个人技术能力的重点。
3.1 C语言基础
1、多看优秀代码,学习其技巧。
2、使用带参数检测的接口,比如优先选择snprintf,少用sprintf,其它str前缀的如strncmp也是,但要明白这类接口和memcmp区别。不同的编译器表现不一致,平时也要多关注。
在GCC中编译运行(设备):
char str[5]; int ret = snprintf(str, 3, "%s", "abcdefg"); //ret = 7 ,str = ab char str[99]; int ret = snprintf(str, 99, "%s", "abcdefg"); //ret = 7 ,str = abcdefg
注:snprintf的返回值为字符串的长度,且写入的字符串后面带有‘