什么是原创能力:造轮子的能力
原创能力是指一个人创新和创造新事物的能力。通俗讲就是逢山开路遇水搭桥。在工作中,如同你为了提升效率而编写一个自动测试框架,或者设计出一种脚本语言以降低C语言的开发门槛,这些都是原创能力的体现。开发者具备原创能力,就能创造出他们所需的各种工具,或者我们常说的"轮子"。
NGINX社区经常造轮子
在NGINX团队工作我的最大感受是这里的开发人员经常造轮子。前段时间NGINX支持了HTTP/3,尽管HTTP/3协议相较于HTTP/1复杂度大幅增加,而且在他们实现之前已经有其它人开发出一些C库了,NGINX社区的开发者们依然能够自主实现。
这种创新精神我认为是由NGINX的创始人Igor Sysoev所引导的,他的原创能力塑造了NGINX社区的DNA。回溯到2002年,NGINX发布第一个版本,当时很少有人能预见它能超越Apache这个伟大的开源软件。之后,Igor开发了NGINX Unit以构建更现代化的应用软件,同时他也开发了NJS,让NGINX具备脚本语言开发的能力。NJS是我加入NGINX之前贡献代码最多的开源软件,加入之后我也将NJS集成进了NGINX Unit。
这些都是大型的轮子,开发周期较长。然而,在日常开发中,我们也经常创造出小而实用的轮子,比如让NJS支持进程内运行任意JS代码,或是让NGINX Unit实现JSON配置解析和原创的路由等功能。
可以这么说,没有原创能力,这些开源软件就无法存在。原创力是开源软件的生命力。
为什么要造轮子
我们可以很容易理解为什么需要创新的东西,比如Python, Lua, Go, Rust,甚至ChatGPT,这些影响力大、存在价值高的大轮子,我们称之为创新。那么小轮子呢,尤其是那些已经存在的轮子,为什么需要重新制造呢?
为了更好用,减少依赖:NGINX的红黑树实现已经很好了,但是Igor在写Unit时,又重新实现了一个新的红黑树,个人感觉接口和实现都比NGINX更好。已经有很多JSON解析的C库,为什么Unit要自己实现一个呢?因为JSON配置是Unit的核心功能之一,我们希望减少对第三方库的依赖,使得软件使用更简单,细节更可控。你会发现NGINX社区开发的软件都是非常容易使用的,很少依赖第三方,编译和安装步骤都是少到不能再少的程度。
好东西经得起时间过滤:我认为创新和协作是开源的两大核心要素。如果有人能写出比以前更好的软件,功能,工具,这就像在经济学中的搭便车效应,他们为后来者提供了更好的服务。
重造轮子的成本并非想象中的高:在开源世界里,我们更追求价值和质量,所以有时候花费几周或者几个月的时间去重造一个有价值的轮子是值得的。
原创能力:程序员的宝藏
Igor非常擅长编写原创功能,比如算法和代码框架,并且他的代码质量都非常高。这点非常重要,开发人员不仅要具备原创能力,而且还要有能力开发高质量的代码。
在开源成为主流的开发时代,如果一个开源软件想要脱颖而出,原创能力是必不可少的。而对于开发者来说,如果想要在技能上有所提升,那么越早开始造轮子越有帮助。如果参与开源软件,这个能力更重要了。
那么如何提升造轮子的能力呢?
人教人不如事教人:只有实践,你才能真正理解和掌握造轮子的技术。当你做过有用的轮子后,你的意识和思维方式会有所改变。
参与有反馈机制的项目:实践的同时要能得到反馈,所以和专业的一起写代码是非常有用的。
多看专业的人怎么造轮子:对比下自己实现会有哪些差异,思考并吸收好的地方。
这是我在探索的一个开源练兵场: 开源星球:成为优秀开源开发者
我为每个功能都建一个issue,你可以提交代码,也可以看这个功能怎么被实现的,也就是怎么造轮子的。有疑问还可以在上面交流。
实际例子: 开发内置JSON函数
这个练兵场项目本身就是一个新的轮子,nginx支持脚本语言是刚需,我自己喜欢官方Lua,所以用它作为一个新的项目。虽然它只是一个练兵的项目,但我要求代码质量和功能都达到产品级别。
这个实际例子是一个新的要造的轮子。
https://github.com/hongzhidao/nginx-http-lua-module/issues/3
Lua是一个极简的语言,它只内置了一些必要的库,如JSON这样的它并未提供。然而有人造出了这个非常有价值的轮子,这是最流行的库。https://www.kyne.com.au/~mark/software/lua-cjson-manual.html
为什么我要造一个新的轮子呢?
首先,我们看看如何使用上面的JSON库。我们假设都以源码方式使用
1. 下载源码,编译安装
> make && make install
这时它会产生cjson.so,而且这个编译要依赖于平台和Lua版本
2. 将cjson.so放在lua path能找到的目录
3. 导入使用
cjson = require('cjson'); cjson.encode(...); cjson.decode(...);
使用并不是问题,它已经很简洁了。但是它有一些不足:
增加维护成本:需要依赖平台和Lua的编译,还要管理cjson.so文件。
实现细节:通过阅读它的源码,会发现直接拿进来用会有问题的,如果内存分配错误,它会exit掉进程。字符串操作它用malloc()和realloc(),但是nginx已经有自己内存池了。这点跟Igor为什么开发njs一样,我们应该为宿主软件nginx打造更匹配的基础功能。
新轮子怎么使用呢?
ngx.json_encode(...);
ngx.json_decode(...);
极其简单,不用编译安装和导入,直接使用。
然而我们也要考虑一些造轮子的现实因素:
打造新轮子要考虑开发成本,我想有原创能力的开发人员这个问题不大,
打造新轮子要考虑稳定性,我们要做的是要有测试用例。
打造新轮子要考虑性能,我会用它跟lua-cjson对比。
关注这个项目,您可以看到对应的提交代码。后续我会分享怎么开发和设计这个功能的。
希望本文对您有启发,觉得有用随手转发
关注公众号不错过精彩文章:(公众号:程序员洪志道)