太子湾公园,终于感受到春天的气息了,周日骑车出来,路上汽车非常拥堵,诶,原来每天的辛勤劳动,也是造成拥堵的原因之一……
开源
Carbon-Lang
Carbon-Lang 关注很久的一个编程语言,官方的一个比喻比较清晰地说明了这个语言的特质。
- JavaScript → TypeScript
- Java → Kotlin
- C++ → Carbon
我认为C++在安全性方面存在诸多问题,这可能与其历史包袱过重有关。
但是这货的编译器本身是C++写的,哪天能够实现自举了,应该也就表示成熟了。话说回来,TypeScript并没有取代JavaScript,Kotlin也没有取代Java,Carbon也不会取代C++,只是在某些场景下,它们更适合一些。
Carbon 的背后当然依靠LLVM的强大支持,这也是很多新语言的选择。实现一门语言,尽管门槛仍然很高,但是相比以前,工作量已经可控了许多。
接下来我关注下他的进展,尽管目前一个靠谱的应用似乎都没有看到。
技术
C++的工程应该如何做好质量保障?
本周开始Review 周边部门的代码,当然两天后我调整了策略。因为在一个没有质量保障的环境下,Review 代码,效果甚微,优先解决当下问题是更重要的。
当然从长远考虑,质量保障是必须的,那么C++的工程应该如何做好质量保障呢?
我对软件工程的质量几乎开始于在Nokia 时期开发5G的经验。2015年在去Nokia 之前,我刚刚带领一个小团队完成了一次颇有成效的重构。 将原来的软件使用C++11进行了重构,引入了一些新的设计模式,性能得到了数倍的提升。在最后第一版的前期,我发挥自己Trouble Shooting 的能力,解决了一系列难题。
而到了在Nokia 时期,我接触到的更多是流程上的质量保护,很少有让我发挥Trouble Shooting 的机会。代码即使功能不正确,也很难引发其他人功能的错误,或者是整个模块的不可用,因为有太多的守护措施。
PR/MR
这个是最基础的,合并请求是Review和一些自动质量门禁的基础。而代码的Review 是最基础的质量保障。但是在C++的工程里面,Review 的代码往往是很难的,因为C++的语法太过复杂,而且很多时候,一个小改动,可能引发了很多的变更。这个时候,Review 的代码就需要更多的时间。
直接PUSH到主分支的代码,是不负责任的行为。
代码风格
代码风格也是最基础的,这个不用多说,尽量保证大家的代码风格一致。否则可能只是一个小改动,在IDE不同的自动格式化下,就会引发大量的冲突或者修改变更数据不准。 当然,在C++的世界里面,clang-format 是一个很好的工具。
静态代码分析
很多公司都会去买SCA的工具,在C++工程里面,Coverity 是一个很好的选择,但是真的太贵了。
对于能够推进Modern C++的组织,可以考虑使用Clang中的clang-tidy 来做静态代码分析。工具甚至根据你的代码风格,自动修复一些问题。当然难点在于clang-tidy 的配置,这个需要一些时间研究,他并不像Coverity 那样,提供了比较完美的默认配置。
至于国内的一些SCA 工具,我就不多说了,基本上就是在集成开源工具,既没有架构上创新,也不存在专人维护检测规则。基本属于乱花钱的行为。
单元测试
单元测试是很多公司会忽略的一点,但是他真的很重要。因为他除了验证软件是按照期望的逻辑在执行之外,基于单元测试,你才可能:
- 单元测试覆盖,根据覆盖率的变化来判断代码的质量变化的趋势。
- UT With Address Sanitizer。Address Sanitizer 这个是一个很好的工具,已经集成进编译器,可以检测内存泄漏,内存越界等问题,但是必须动态执行,所以在单元测试里面使用是最基本、也是最高效的拦截内存错误的方法。
- 代码重构。单元测试是重构的基础,因为你可以保证重构之后的代码,和重构之前的代码是一致的。
性能分析
如何保证代码的性能呢?这个是一个很大的话题,但是在C++的世界里面,性能分析是必须的。因为C++的性能问题,往往是很难定位的。而且很多时候,性能问题是随着时间的推移,逐渐暴露出来的。
定期进行性能分析是必要的。如果条件允许,应该对原子代码进行定期自动化性能测试,并通过Promethus、Grafana 这样的工具,将性能数据可视化。及时发现性能回退的问题。
安全性
更多地需要依赖Review,当然类似Coverity 这样的工具,也可以检测一些安全问题。但是相关安全规则的配置是一个漫长的Tunning的过程。
持续集成
以上所有措施,必须要有持续集成的支持。缺乏了自动化的持续集成,很多措施都是无法实施的。效率和质量是矛盾的,但是持续集成可以让你在效率和质量之间找到一个平衡点。
但是话说回来,谁知道呢未来如何呢?端到端的思路,我们应该只要关注需求的输入和最终实现的正确性,剩下的都交给AI去做吧……
性能优化感悟
最底层的代码优化,往往带来的提升是巨大的。优化顺序:算法 > 数据结构 > 代码细节 > 架构设计。
当然,往往架构设计决定了代码细节的优化空间。
重新回顾了一下 卡马克常数,有生之年,恐怕无法抵达 1/100 的境界。
“卡马克常数”:指的是约翰·卡马克(John Carmack)在《雷神之锤III》中使用的快速平方根倒数算法中的一个神奇常数(0x5f3759df)。这个算法以其高效和巧妙而闻名。