格物致知

前言

我记得在很小的时候,“格物致知”这个词就已经被王阳明格竹子的故事玩坏了,书本上故事的基调是某个傻子按着腐朽的儒家思想去实践,最后把自己搞病了的故事……如果能遇到当时写故事的作者,真的很想揍他一顿。前段时间在解决完一个纠缠两周BUG后,突然想到了这个话题,今天在知乎、维基百科和奇摩上逛了几遍后,感觉能写一个开头了。

“格物致知”的出处在《礼记.大学》,“欲诚其意者,先致其知,致知在格物。物格而后知至,知至而后意诚”。

朱熹的回答是,“格,至也。物,犹事也。穷推至事物之理,欲其极处无不到也”,”推极吾之知识,欲其所知无不尽也”,虽然事物之理和科学道理没有太多关系,但总体接近现代科学的角度,多方面去解析、辩证事理。理论归理论,不同的人操作起来结果天差地别,穷经心力琢磨解决事情的方法,但一到现场就懵了。

王阳明的回答是,“无善无恶心之体,有善有恶意之动,知善知恶是良知,为善去恶是格物”,正内心,致良知,听起来修仙的老道士,但这是一位实干家的回答,只从他剿匪平乱杀敌的记录看,完全就是个狠人。

烦人的BUG

接着上一篇:Golang笔记–04–GPIO与中断

回到那个烦人的BUG,最初的代码在树莓派3B上运行正常,而在树莓派zero w到手后,就陷入运行死机、找不到日志的状态,琢磨一下午都没找出问题,此外在树莓派zero w上,Go程序一直无法编译成功,让人恼火。由于Go运行时和标准库的功能都是由Go、汇编及系统调用实现的,首先想到的就是官方镜像的内核不完善,第二天升级了树莓派zero w的内核,早上试着切换到Python,凉了,下午回到Go,找了一个星星数少了很多的库(作者按照另一种协议实现了功能)替换,修改,成功编译运行,之后顺手给原来用的第三方库提了一个issue,然后蛋疼的日子刚刚开始。

首先搜集了树莓派所有型号的参数,除了CPU外引脚分布、系统、Go版本还有代码都是一样的,感觉问题不在这里,然后把在用的两个Go开源库看完,也找不到毛病,换了新库后还遇到输出数据混杂的情况,就补了一遍Unix文件系统,然后把RPI.GPIO的代码看了一遍,觉得问题出在获取设备地址,在issue上补充了示例代码,同时下了最新的Linux内核源码,把SELECT、EPOLL这些IO多路复用的源码看了一遍……还是找不到问题,接着提的issue有了回应,也有人遇到同样的情况,作者在老版本的系统和Go环境下正常运行,问题又回到Linux系统和Go了,这时候差不多过了一周多。

这种难以复现又毫无头绪的BUG是最令人讨厌的,虽然换了新库解决了当下的问题,可是BUG是不可能不管的。开始读Go源码后就把issue的事情抛在脑后了,直到那天下午看到关于Go支持的处理器架构部分,联想到出现过一次的illegal hardware instruction,重新把老代码在树莓派zero w上编译了一次,成功,然后在mac上交叉编译了一份程序,拷贝到树莓派zero w上,复现了错误。问题在于交叉编译中缺少了某个指令,排查后是GOARM的默认值问题。

短时间内我有种眩晕的错觉,感觉变成表情包了,昨天下午和同事聊天的时候提起这个问题,他说我怎么会发现这么蛋疼的BUG,我也想知道怎么会陷入这么蛋疼的问题?如果换到两年前的自己,除了切新库外,应该也会卡在解析BUG的过程中……好像从来就没变过,而更多的疑惑是:这个开源库都有长达5年的历史了,为什么作者没有发现这个问题?

代码是人写的

代码不是天上掉下来的,但在很长时间内,我都有一种标准库和IDE是天然存在的感觉。

在看Linux内核TCP/IP部分时,遇到一位作者:Alan Cox

6年前就开始使用Linux,4年前开始使用HTTP协议,这两年也做过IM和基于长连接的物联网设备对接,甚至在大学里也上过一节又一节的计算机网络课程,但是,从来没有考虑过TCP/IP协议本身的实现过程,直到看了Alan Cox的代码和注释,关于他的维基,还有各种相关的新闻,才深刻感受到,即使是最底层的软件,也是有具体的,活生生的人来实现的,当我们在阅读这些源码时,又是否可以感受到作者们在逐步修改优化时想法?

底层标准库会给人一种稳健牢固的感觉,就像NGINX给人的感受一样,但只要是人参与的活动,就有引入各种人的问题,回想之前心脏出血的漏洞,也是代码实现的错漏造成,由此联想到物联网设备使用的蜂窝网络模块,它提供了基于TCP/IP的套接字通信,使用者也是按这个假设来使用的,但却无法保证它是否完善地实现了协议。有点像Go语言中interface的概念,符合interface定义的对象特性是“has a”而不是“is a”,后者宛如潜意识上认定拥有了完善的interface特性,也是我们常做的,如果最初能能换一个角度去考量协议实现的完善程度,也不会陷入现在的泥潭了。我们在做的都是面向协议的设计者与实现者的编程,而不是协议本身。

PS:更早的时候想要做一个类似LKL能够更改网络参数的服务程序,搜索相关知识时,在论坛上碰到一个问题,Go语言为何依托操作系统提供的网络功能,不自行实现TCP/IP协议栈?有意思的是,正好有一位参与过协议栈实现的回答者,他们一开始欢快地实现网络协议栈,中期卡死,与其他设备通信时总是出现奇怪的问题,后期全面败退,惨淡收尾,完全低估了网络世界的复杂性,以血的教训给出了一个回答:不要轻易使用自定义的网络协议栈。

Long Live Open Source

之前和硬件工程师在关于长连接保活问题上吵了很久,关于如何实现保活,我认为类似MQTT以及TLS 1.3的模式可以做到相对健壮的机制,参考实现服务端策略,也按照预定的协议格式做了安全检查,但硬件工程师的思路总是往我认为不合适的方向走,例如要求完全放开协议格式检查、服务端永不断开连接,长连接的心跳时间都已经缩短到60秒左右一次,但设备掉线重连时却要长达十分钟以上,这对于实时性要求高的设备是无法忍受的。后来自己看了通信模块文档,它只提供了基于AT指令的操作,在设备上根本无法做到和服务端一样直接管理长连接,想进一步优化长连接的话,只能继续摸索文档提供的指令和设备特性,还有参考以前的经验。就像之前写App遇到问题时,不常见的问题到最后基本就是系统的问题,只能摸索定位问题,去适应它,优化它,然后等待苹果公司修复问题,这种感觉很糟糕,宛如黑盒测试。

之前看自由软件运动的故事时,提到在早期,设备厂商会把软件源码随设备提供,以便使用者在出现问题时自行修改,但后面厂家开始闭源,设备与软件绑定在了一起,例如一台打印机只提供了Windows XP的驱动,在高版本系统上出现打印错误,厂家也无心修复设备的软件问题,那么该设备最终只能走向废弃。当然,这只是个不恰当的例子,如今的软件开发复杂度逐渐提升,即使提供了源码,也很难去修改,主要问题是难以消化源码依赖的知识体系,这段时间刚好遇到了这种情况。我们使用的地磁检测模块在长期使用后会出现异常的问题,而设备厂家打算取消这块业务,不再投入人力,几经协商最后拿到了源码。我们几位软件工程师,为了读懂源码补充了许多地磁场的背景知识,还是看不懂,然后制作了采集器,收集了数据再测试,稍微摸清了源码,也给出了一套修改后的算法,至于测试结果如何,还没有定论。

软件的源码(包括那些公布源码,加个证书就不再维护的项目),在很多情况下只对直接使用者有意义,能够通过修改获得明显的收益,其余的吃瓜群众和专业不对口的人士即使拿到了源码,也连读懂都很困难(例如让一群软件开发去优化硬件代码),没有产出或者回馈的话,从结果论来看是没有意义。可是对于菜鸟来讲,很多时候即使无法解决问题,也会在摸索问题的过程里得到很多收获,形成自己的思考,就像软件开发中,你无法预测会出现哪些,最有效的方式就是长期的持续积累,当到了某个点,一切串联起来时,就会得到巨大的收益,这是我一直认定的道理,首先需要有探索到底层原理的毅力,其次才需要源码,而开源行为本身恰好提供了这一点,满足了许多折腾人士的求知欲。

总结

从落笔到写完,只过了两周时间,随着认识的改变,想法也在演变,换句话说,是意识流派系的,在百科上看到关于意识流的解释也很符合:个体的经验意识是一个统一的整体,但是意识的内容是不断变化的,从来不会静止不动。这也导致自己在写博客时,必须挤出一大段的时间,经常是整天或者整个周末,让思绪连贯,因为一旦中断,后续的认知又会冲刷之前的想法,会下意识地认为自己是否写得不连贯,是否表达出自己想要的东西,如果是别人看到这篇文章,对他来说,是否又是连续的?太多的想法以至于无法理清,不断地否定过往的想法,但核心一般不会改变,因为它是无法描述的。

格物致知,一是计算机中事物之理,代码只有非黑即白的结果,何况是它由人构建的体系,通过不断学习串联起知识,总会得到确定性的结果,二是关于态度,为没有定论的问题确定结果,无论花费多长的时间,多少的投入。

发表评论

电子邮件地址不会被公开。 必填项已用*标注