任何足够先进的技术都与魔法无异。——阿瑟·C·克拉克
这句话不仅适用于非技术人员,同样也适用于开发者,有时甚至更为贴切。我回想起自己在编程之旅的初期(无论是18年前第一次学习编程,还是大约15年后再次开始),导致所谓的“教程地狱”(我个人很讨厌教程,总是选择尝试自己动手构建东西,并认为这正是我取得相对成功的很大原因)的那种感觉。
情况是这样的:
你觉得已经完全掌握了如何正确使用锤子、砌砖、安装石膏板以及如何用锯子测量并切割木梁的方法,但当你看到建筑物和建筑结构时,仍然觉得那些你已经学会的工具竟然被用来建造这些宏伟建筑是一件非常不可思议的事情。你不知道从何开始,只能盯着手里的工具、材料,怀疑他们是不是有某种特别的设备或秘而不宣的知识。你无法理解他人是如何用这些同样的工具达到那样的结果,甚至无法想象应该如何切割第一块木板或铺设第一块砖。
许多人都知道,这就是学习编程的感受,完全掌握了循环、变量、数据结构、树、栈、链表、数组、控制流等概念后,看着编译器、视频游戏、操作系统或Web浏览器时会感到“是啊,怎么可能……”。这些开发者一定都是从小就开始用C语言和x86汇编编程,并且都在斯坦福大学学到了Kern Thompson传授下来的秘密知识,由Brian Kernighan本人亲自教导。
假设你不走严格遵循JS框架和vercel用户的路线:随着时间的推移,你会逐渐发现一些模式。你通过“转到定义”查看你使用的库中的方法实现,并构建了足够的辅助项目,观看了大量的“tsoding daily”、“sphaerophoria” 和“awesomekling”,逐渐解除了网络协议、图像/视频编码或系统调用/文件输入输出操作的一些神秘面纱。如果你现在需要写一个shell或Lisp解释器,你至少会知道首先需要把源文件读到内存中,并将其拆分成标记,再试图解析它以构建所需的语法树,这样你才能遍历并分析它,最后逐步执行代码。之前你觉得理所当然的事情,在此刻感觉就像是一种只有前述编程精英才能掌握的魔法。
我相信我不是唯一有这种感受的人,在揭开每个看起来像“魔法”的面纱时,都会产生这样的想法:
噢哦哦,原来是这样啊。当然,那还能怎么弄呢?真不敢相信我居然没能看出这一点。
随着时间的推移,遇到难以理解的问题越来越少,即使是粗略地从高层次角度去解析,也能对实现的大致情况有一个基本的认识。虽然我不敢说我了解内核内部细节、3D渲染或GPU驱动的工作原理,但大多数事情已经失去了那种模糊的神秘感,变成了我可以充满兴趣去了解的东西,而不是一种令人生畏的禁忌知识。不过对于那些领域来说,这也许是确实如此吧;)
前几天,在管理不同环境/k8s集群工作了一天之后,我习惯性地逛了下Hacker News。我遇到了一篇提及Go的comptime功能的文章,并附链接到github仓库。立即引起了我的注意。虽然我自己并没有使用Zig编写过程序,Andrew Kelly是我敬仰的一位编程偶像,我确实一直关注Zig的发展。Comptime是Zig最令人羡慕的语言特性之一。虽然其他语言通过元编程或constexpr可以实现类似功能,但Zig的直接过程式方法/API使其格外独特并受到称赞。
当我遇到那种熟悉的感觉时:


如果你告诉我必须不修改编译器来实现在Go中实现comptime
所以我决定要一探究竟,于是花了几个小时时间试着贡献一些什么,或者至少添加某种级别的有用功能,强迫自己去理解这一切是怎么回事。
然后经过短暂的代码浏览……
原来你可以利用通过Go在编译时传递的一个标记-toolexec获取的源文件信息,这个标记允许你调用工具链程序,在这里指prep二进制程序,该程序通过绝对路径调用来实现AST、文件装饰者和导入恢复器的功能,并通过实现Modifier从而收集树中相关函数的变量,将它们分别输出到临时文件中,并运行解释器,这样就能得到prep.Comptime(foo())计算的结果,最后通过Modify阶段替换DST中的值。就这样,你实现了编译时计算。
哦,没错,这完全说得通。我是怎么以为这能通过其他方式工作的?
经过几小时的努力,我添加了变量作用域和全局常量声明的功能,后来我发现其实这并不是一个有用的特性,因为每个函数都是单独评测的,实际上几乎不存在命名冲突的可能性。但重要的是,直到写完并通过测试,我才得出这个结论。虽然这个特性没有任何实际价值,但整个过程是非常宝贵的学习经验,是一次非常有价值的时间投资。
这是对所有处在不同开发阶段的大家的一个提醒,那就是所谓的“魔法”并不存在,绝大多数时候只是因为缺乏必要的上下文,一旦你有了这些上下文,一切都会变得豁然开朗。
花时间学习你每天不一定能用得上的堆栈部分总是值得的。当你逐渐建立基础知识时,这会让其他本来无法联系的部分变得清晰可见。即使现在感觉不重要,但我保证未来某个时刻这种知识会为你带来回报。
持续每天学习,追求更深层次的理解,花时间构建甚至被认为已解决的问题。即使你只被雇佣来写React,了解其内部实现原理或你的“一键式”无服务器自动扩展部署工作原理都是非常有价值的。
