2019年就快过去了。 这一年最开心、最高兴的是,我参与研发的“全自动生化分析仪”终于问世,很受市场欢迎。 由于有一支非常有力量的销售队伍,机器的订单一直在进行。 当然,成功开发机器是项目经理和团队的功劳,我只是参与了其中的一部分,但这对我有特殊意义,因为这是我的第一个基于linux的商用上位机软件。 以前在windows平台上挥舞过java、C#、MFC的小上位机,这些上位机在代码量和功能上是该商用上位机无法比拟的。 毕业设计的时候,看到了linux系统功能的强大,想从事linux系统的软件开发; 但是,为了尽快找到工作,只能先找擅长的单片机和stm32的软件开发工作。 然后利用业余时间学习有关linux系统的知识。 由于没有合适的指导,学习linux系统的APP应用程序开发选择了很多绕道而行的课程,根据课程先学习了linux的设备驱动程序开发,然后学习了linux某个模块的源代码; 这一部分在以后的工作中也用了一点,但这只是与Linux APP开发方向不同的工作; 直到2016年初,我才学会如何在linux上开发Qt APP应用程序; 直到2016年底,造化终于有机会让我开发基于linux的APP应用程序。
加入项目团队时间晚,加上开发者第一次使用上位机,没有经验,没有针对需求进行详细的软件体系结构设计,所以马上开始根据需求进行编码; 用这种方式开发一些学习软件没有问题,但开发功能丰富的商用软件是绝对不可取的; 鸡舍前期不用图纸,盖高楼,前期没有详细的规划和图纸,就会带来无限的问题。 前期没有详细设计软件体系结构,而是根据开发单片机软件的经验用c语言思维开发c软件,刚开始开发调试执行机构的软件,没有发现有什么问题。 随着功能的增加,代码量越来越大,致命问题层出不穷,特别是在处理测试数据时。 项目经理测试机器性能时,整个软件的错误满天飞,黑屏不断。 项目经理一直在推动进展,但不是给我带来很大的压力,我相信我能改善。 刚开始调试bug的手段比较单一,只是把程序运行情况打印到控制台上,这是一种常用的调试手段,但局限性也很大; 因为机器在不同的地方使用的时候,必须在那台电脑上安装串行调试助手才能知道机器的运转状况。 如果交给客户使用呢? 经过不断查阅资料,Qt提供了运行日志的功能,以前有通信日志,但这是不够的; 掌握Qt执行日志功能后,将此功能添加到软件中; 果然收到了很好的效果。 无论计算机在哪里运行,只要出现问题,就可以根据执行日志和通信日志立即确定原因,但打印执行日志时会考验经验。 打印过多会影响软件的性能,打印少则不利于确定原因。 但是,在开发软件的阶段看到一些变量值,每次都要登录后台打开运行日志进行查看,很繁琐。 根据开发单片机软件的经验,每次出现bug都是模拟,因此引入了GDB调试。 使用的开发环境版本较低,无法一键远程调试,但使用GDB服务器的方式也能达到同样的目的。 使用GDB调试后,可以导航到软件运行的特定语句并检查变量值。 开发效率大幅提高。 一个朋友问我为什么在linux的APP应用程序崩溃时获取linux的酷睿文件,定位器崩溃,我直接问:“不! ”回答说。 然后,朋友用轻蔑的眼光看了我一眼。 那轻蔑的目光久久不能忘怀。 没有学艺的本领,只能在轻蔑中成长! 并查阅了大量资料,进行了相关实验,了解了linux的核心文件是什么和如何使用的; 如果linux的core文件在Linux APP应用程序崩溃如飞机失事后的黑匣子)时显示黑色屏幕,则core文件会记录APP应用程序上次执行的各种情况,然后在GDB中调试core文件您可以根据核心文件确定问题类型,并根据运行日志确定特定原因; 将两种调试手段组合使用。 在开发软件的过程中,总是会遇到各种各样的错误,但丰富的调试手段决定了能否及时找出原因并解决错误。 从最初遇到bug的慌张到最后的淡定上述几种调试方法给了我很大的底气。
虽然掌握了几种调试方法,但可以相对快速地确定错误的原因,但不能保证整个工程的代码质量。 由于前期缺乏整体软件体系结构的设计,到了中后期,在代码维护和进入新需求时,修改代码时总是“一蹴而就”,修改一个错误往往会引入另一个错误。 新功能是影响其他功能。 整个软件项目就像豆渣项目。 为了扭转这一势头,我买了很多书,或者在网上找相关的视频教程。 你经常买那么多书看完吗? 当然读不完,但书只要有助于解决小问题就赚钱,而且有些书不仅有助于解决问题,还能带来系统的知识点。 寻找各种相关的视频教程是为了看其他大神写的代码。 因为提高编写代码的能力就是看和模仿大神写的优秀代码。 以前购买的教程学习小组里有人介绍狄泰软件学院的课程,由于以前购买的课程的影响,刚开始我也犹豫了一会儿,后来问题太多了,抱着试试的态度,价格也不高就买了QQ课程; 一上课就有“见面很晚”的感觉。 课堂上看到写几个小项目讲解知识点的老师写小项目代码,总是觉得醍醐灌顶,本来就可以这样写代码; 其中项目接口的所有代码生成都为使用代码生成接口提供了模板; 有时会巧妙地运用抄送的各种基础知识而不是简
单的“if else”和“switch case”;例如把C/C++的“短路原则”、“条件表达式”和“逗号语句”的作用发挥得淋漓尽致使得代码简洁清晰;因之前看过整套C++视频,这些基础知识虽然都懂,之前却不知怎么样使用;这让我坚信了基础知识的重要,只有基础知识扎实才能写出有质量的代码和设计出工业水平的软件架构。看完了这些再对照自己写的代码,然后通过模仿课程的写法几乎重构了整个软件代码,也重新设计了整个软件的编码风格。
虽然整个软件有了良好的编码风格,但却找不到解决界面与数据分离的方法;直到看了课程中讲解的自定义模型类,用分层思想实现了数据到视图的控制流程,每层用一个类表示,用自定义的模型类组合了标准模型类,灵活显示各种数据;定义数据源类操作底层数据文件,用于把数据对象转换成字符串写入数据文件,让上层代码只需操作数据对象即可,妥妥的面向对象编程;这样就使得程序结构层次分明,代码写起来简单明了便于维护。这套设计我只需做简单的修改,增加少量的代码,即可用于解决我的软件界面与数据分离的问题;这套设计还让我学会了如何面向对象编程,就是在解决问题时,先把问题抽象成类,然后再定义操作类解决问题后返回相应问题对象。这种思想在课程实现简易网络聊天软件时得到了进一步的体现。在解决网络通信的数据粘连时,定义了通信协议类,然后定义协议对象装配类用于把通信数据装配成协议对象并返回给上层代码处理;通过举一反三修改少量代码即可用于解决我软件的串口通信数据粘连的问题,相比于原来用C语言思维方式解决问题,代码显得有层次有模块,完全符合“强内聚弱耦合”的设计原则。
有了灵活巧妙运用各种基础知识的模板,有了如何用代码生成界面的模板,有了界面和数据分离的模板,有了运用面向对象编程思维解决通信数据粘连的模板;接下来就是模仿这些模板写法,重构自己的软件代码;而整个工程代码将近十万行,几乎是全推倒式的重构;而现实情况不可能是接下来几个月不新增需求和修复bug;所以只能“乱中求治”,在新增功能和修复 bug时坚持“抠”一点时间或利用加班时间用于逐渐改善代码设计,逐渐使代码的质量越来越好。最终使整个工程代码层次分明,结构简洁清晰,模块化,为后期维护打坚实基础。
在完成整个软件的功能中另一个困难就是各种非线性曲线的拟合,刚开始面对这种只有在研究生课程才会学到的数值分析束手无策;后来由于时间关系,这部分就交给另一个同事,他用开源库搞定了。但由于对其中各种拟合曲线的兴趣,我开始翻阅各种资料,慢慢发现可以看懂简易的样条曲线拟合推导过程;这更激起了我的兴趣,更加认真学样条曲线拟合推导的全部过程,学习的过程就像sqdjd破案一样,一点一点的接近真相,每次有进步一点都能让我兴奋不已;先是在直率的大白和ssdds编写的《数值计算方法》学了样条曲线拟合的推导理论知识,并看懂其中的几道例题;然后在王晓华编写的《算法的乐趣》学会了把方程组变化成矩阵,通过刻苦的板凳脱法分解成两个三角矩阵,再用追赶法求得方程组的解。最后在John H.Mathews和Kurtis D.Fink著的《Numberical Methodes Using MATLAB》了解了样条曲线端点约束的几种情况,对样条曲线有了全面的认识;同时也知道机器中样本曲线拟合适那种端点约束。结合几本书学到的知识点,最后编写成了代码,并且计算结果和用开源库拟合的曲线参数是一样的,这让我成就感爆棚。拟合曲线完成后,在计算测试结果时,则是让我学会了用牛顿迭代法求解一元三次方程;还有如何快速判断抛物线在一个区间内的单调性,妥妥复习了一下高中数学。
从写下第一行代码到软件跟随机器上市,这个过程遇到过千千万万的问题,而每一个诡异的bug和问题背后都隐藏着一个低级错误,每当解决一个诡异的bug都能带来一点点成就感和一点点进步;这也是我从毕业后这几年来,一直坚持学习linux应用开发的原因,虽然这几年让我失去其他的很多东西,思想也有过波动,最后庆幸坚持了下来,终于有一款基于linux的商用上位机,也算是随了几年前的心愿。
2019年12月31号