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