09月30, 2018

从抄书到开源之巅:章亦春的程序人生

春哥的编程之旅起于抄书,就算如今已是罕见的编程高手,春哥依然逢人大力推荐他的抄书学编程之法。春哥先后在中国雅虎、淘宝、Cloudflare 就职,但开源世界是他如一的眷念。如今,春哥已全身心投入 OpenResty 的崭新蓝图,期待 OpenResty 未来能在工业界、互联网行业引领“机器编程”革命。很荣幸这次图灵访谈可以对话春哥,让我们来一起了解一下春哥的快意程序人生。

春哥,本名章亦春,开源项目 OpenResty 创建者和推动者。

春哥的时间线(毕业之后):
2007 年 也就是我大学一毕业,加入中国雅虎搜索技术部。当时的中国雅虎已经是阿里旗下的一家公司了。那次工作机会源于我在毕业前夕受邀在 PerlChina 北京大会上作的开源分享,而那次大会正好是在中国雅虎总部举行的,当时有幸认识了中国雅虎的搜索团队(又称 4E 团队)。
2009 年 被调到淘宝数据产品与平台部,集中力量和同事们一起基于 OpenResty 开发淘宝量子统计这款产品,主要面向淘宝卖家。
2011 年 我离开阿里,和夫人(当时还是我的女朋友)一同前往一个陌生的南方小城福州,过了一年所谓的“田园生活”,在家里全心从事 OpenResty 等开源项目的工作。
2012 年 我受 Cloudflare 公司邀请,举家来到美国湾区,全职从事 OpenResty 开源开发,以及基于 OpenResty 的全球 CDN 网络的软件系统的研发和完善。
2016 年 晚些时候我离开了 Cloudflare,并于 2017 年初在美国创办了 OpenResty Inc. 公司。

母亲、赛扬与抄书,我的编程起点

我最早和编程结缘,说起来还是托我妈的福。上初中那会儿,记得是 1999 年的时候,她正在准备计算机二级自考,于是家里买了一台赛扬 330MHz CPU 的机器,装的 Windows 98。她也弄了一本谭浩强的《C 语言程序设计》教材,经常放在家里。自然,我经常去玩机器,系统里唯一一个打开来不知道该干嘛的应用程序,就是那个奇怪的 Turbo C 编程环境。双击打开后,蓝色的屏幕上光标一闪一闪的,我完全不知道该干嘛。这激发了我强烈的好奇心,一心想着也能把它玩转,就像使用 MS Word、AutoCAD 这些不用人教就能熟悉的应用程序那样。

初中毕业之后,我就“偷”走了那本《C 语言程序设计》,仔细研读起来。我妈当时是强烈反对我学习编程的,她认为我这是“不务正业”。当时,身边除了我妈没有人懂编程,我便只能靠自学。由于完全没有编程的概念,即使从第一页开始一个字一个字地手抄,也还是一头雾水,不知所云,感觉很郁闷。2000 年,我刚刚高一开学,当时我所在的高中——镇江一中,发给我们的一本《计算机基础》教材,里面有讲解 Visual Basic(VB)的章节。我觉得貌似比 C 语言容易很多,于是又开始手抄这本教材里的 VB 章节。我每抄完一段,就反复研读。这样折腾了几周,终于明朗起来,有了编程的基本概念。于是,又回过头来继续手抄那本 C 语言教材,抄到一半左右的时候,我终于感觉到可以不用继续手抄了。然后,我就陷入琢磨如何用 C 实现各种链表和其他复杂数据结构的细节中去了。高一寒假的时候,我又开始手抄 Thinking in C++。寒假结束时,我对 C++ 语言算是比较熟悉了,也就不再满足于 Turbo C,开始玩更高级的 IDE,像 Borland C++ 和 Visual C++ 。

回过头看,抄书是我自学编程的法宝。话说抄书这种学习方法是我意外间发现的。初三时,我酷爱化学,总是缠着当时的初中化学老师提各种奇怪的问题,老师拗不过,借给我一本他当年大学时用的课本《分析化学》。我如获至宝,爱不释手,但借的书总要还,但又不能立马消化,于是我便抄书,抄了整个暑假,结果意外地发现了抄书的奥妙——那就是延缓阅读速度,不至遗漏每一个重要的细节:眼到,手到,心到。

其实不仅书抄得,代码也抄得。记得我刚进入淘宝时,想学习 Nginx 源码。于是白天上班就对着 Kindle 抄 C 源,同时就已暗记于心;晚上回家在房子里来回踱步,在脑海中反复回放白天抄过的源码,直至融会贯通,深得其奥妙。这段日子持续了一两个月后,便大彻大悟了

教机器解题,编程和高考之间的平衡木

入门以后,我就对编程越来越有兴趣。只要不上课,我就会跑到新华书店去看一些编程类的书。整个高中三年,那里都是我最爱待的地方。同时,以高考为目的的学校教育也愈发让我反感,我觉得完全是在浪费时间。虽然我上的是当地的重点高中,学校也倡导所谓的“研究性学习”和“素质教育“,但高考的压力从高一就开始了。一方面是编程的巨大乐趣,另一方面是高考为指向的应试教育,这让我非常痛苦,甚至都动过辍学的念头。

我于是和爷爷讨论解决的办法,因为我俩既是祖孙也是朋友。他当时帮我出了个主意,就是想办法把编程和高中学习结合起来。具体怎么结合,只能我自己去想了,我爷爷也完全不懂计算机。认真想了很久,我决定亲自教机器去解答各科的高考题。而要教机器解题,我自己首先得学会如何解题。这给了我继续应试教育的理由。

当然,教机器解高考题对于一个没有人指点的高中生而言,显然是一个很大的挑战。那些高考题即使对于人类也是很有难度的。我不得不拼命自学了很多艰深的计算机专业的课程,像编译理论、自动机理论、专家系统、人工智能,还阅读了一些论文,比如定性推理之类的研究成果。

机器解题与人类解题的一大区别是,机器不能运用人类直观来辅助解题。比如几何题里作辅助线,或者其他基于视觉的解题方法,这些对于机器都是不适宜的。机器需要精确的推理方式,需要把一切都形式化。我不得不研究了很多反常规的解题方法,因为其中一些方法运用了高等数学的知识,在真正的高考中也是不宜使用的。记得高三时,我还自己定义了一种简单的数学系统,可以漂亮地证明任意立体几何的定性证明问题,而不依赖于任何人类直观或辅助线。可惜的是,以当年的数学素养,我只能证明数学系统的内部相容性,却无法证明完备性。不过,当时搜集到的高考题都可以用那个自动证明系统证明。(上了大学,我才有时间完成证明系统的代码实现)。

高中三年对我来说是极为丰富的三年,也是非常辛苦的三年。当然,高考成绩并没有那么理想,我想,是因为追求的深度和广度无法很好的兼顾吧。幸运的是,高考分数还是超过了本一线,应该也是当时班上的倒数了吧。我在江苏大学的四年也是非常充实和享受的,自认为真正实践了高中母校“研究性学习”的口号,走出了一条适合自己的路。

我非常感谢爷爷当年的鼓励和启发,让我坚持完成了学校的教育,也从人工智能和机器解题的角度发掘了学校教育动人的一面,优美的一面。这是我最初无论如何也无法预见的。

大学,步入开源世界

大学时代,最成功的事情有两件。

一件是继续高中时的学习方式,教机器自动求解和证明大学课程的各种题目和问题,比如非线性电路的自动分析、离散系统的仿真引擎、实现 x86 CPU 指令集的指令译码器的硬件设计、计算机程序的自动形式化证明,等等。另外,在计算机上编码并测试那些高中时设计好但一直没空实现的高考题求解系统。

另一件事情是,接触并融入到开源世界。直到现在,我还记得第一次给一个开源网站写电子邮件时的激动心情。虽然只是报告了一处笔误,没想到网站的维护者很快回复了并感谢我的报告,一下子整个人都欣喜若狂了。大三时,我开始关注 Perl 6 这个开源项目,每天都要仔细翻看他们在 freenode 服务器上的 IRC 频道上的聊天记录。我发现这些“老外”说话的方式和从前在英语课本上看到的有很大不同。有非常多的习惯表达方式,也有一些互联网上专用的俚语。就这么通过聊天记录,我掌握了开源世界的口语,也熟悉了频道里经常说话的大牛的脾气和说话方式。认真“潜水”了一年之后,我开始在那个频道里说话,渐渐融入了社区。

随后,我也积极地做了不少有趣的开源代码项目,贡献给了 Perl 6 社区。大四时做了一个Perl 6 语法分析过程的可视化调试工具,居然得到了Perl 的发明人 Larry Wall 的赞扬,这是莫大的鼓励!Larry 在 IRC 频道里是这么评论我的工具的:“agentzh: please allow me to say I'm amazed!”聊天频道里有各种各样的人,有的是美国某大学的博士研究生,有的是西方某艺术学校毕业改行做程序员的,有的是像 Larry Wall 这样的重量级宗师,拥有各种性格、背景、文化的人在一起相互碰撞,相互交融。这种体验让我沉醉其中,无法自拔。开源社区和 IRC 把我和整个世界紧紧地联系在一起。

大学的岁月比高中自由了很多,轻松了许多,身心得到了前所未有的解放,下面这些瞬间让我印象深刻。

  • 白天在江苏大学藏书丰富的图书馆里淘书,面对着各个学科的英文版教材,心中充满敬畏与喜悦之情;
  • 晚上在网上和开源社区跟分布在世界各地的黑客一起做各种有趣的开源项目;
  • 夜里回到男生宿舍熄灯后,又跑到对门宿舍和志同道合的同学海阔天空,热烈地讨论我的一些有趣的新想法——当然,一般是和科学或技术相关的了,经常被查房的大爷打断。即使后来我不再住学校宿舍,也会经常去那间宿舍坐坐;
  • 累的时候在江苏大学那优美宽广的校园里一圈一圈地漫步,心中思考着一个又一个有趣的科学或技术问题,有种“天高任鸟飞,海阔凭鱼跃”的豪迈感。

英语,联结全世界优秀的程序员

英语是国际化的前提之一。前面提到,第一次通过电子邮件和国际开源世界发生联结时,我才真心体会到熟练使用英语的巨大力量。如果编程语言让我们和机器联结,英语则让我们和全世界优秀的程序员联结在一起

高中时,我还主要看中文版的技术书和科学书,步入大学,我就只看英文版图书了。必须承认的是,最先进的技术通常源自中国以外,以英语书写。所以中译本会大大滞后原英文版,很多比较生僻的领域,甚至都找不到中译本;另外可能是译者专业水平和语言功力的原因,中译本的错误也比较多。举一个例子,裘宗燕老师曾经翻译过《程序设计实践》一书,高一时买来反复精读了好几遍。上了大学以后,我在图书馆里竟意外地看到了英文原版,不得不感慨原版还是要清晰和流畅许多。

出于国际化的考虑,从大学开始我做的开源项目也都用英文写文档,只有极少数情况下我会加上中文译文,因为翻译对我来说确实是很无趣的工作。英语是和世界沟通的桥梁,OpenResty 后来的国际化也得益于此。

工作,最难得的是:跟对人

参加工作之后的这些年,经常收到一些关于工作与实习的咨询。我个人的观点是:只要有机会跟着牛人干,不论具体做什么,都是会有很多收获的。工作内容不重要,跟对人最重要。如果能有机会和自己景仰的人一起工作,不给钱我都愿意。当然,这个确实要看机缘,是非常难得的事情。

毕业后,刚加入中国雅虎的时候,我做的工作经常被一位比较资深的后端工程师批评,最狠的一次算是“垃圾批量制造”这样的话。但我从他那里零零碎碎地学到了很多高性能互联网应用系统的实现方法和设计思路。再后来加入淘宝以后,我拜了一位当时看来很“神”的工程师为师。他也经常把我骂得狗血淋头,在他的指导下我们一起创建了第二代 OpenResty 平台,我也学到了很多基于 C 的系统编程技术。

不过话说回来,开源世界确实没有什么门槛,只要自己努力、有意愿,就完全有机会和不同的世界级牛人一起协作,不必拘泥于同一家公司共事的形式。从另一个角度看,公司的工作环境一般会比较复杂,也远没有开源社区那么简单和纯粹(当然,开源社区也有政治斗争,敬而远之便是了)。

所以,我建议还在学校的同学多拥抱开源,最好是参与国际性的开源项目,加入对应的国际性开源社区。以我自己的亲身经历来看,开源世界的工作是最好的简历。大学毕业之后,我基本上没有主动找过工作。阿里的工作机会也好,美国 Cloudflare 的工作机会也好,都是工作找过来的。我在阿里待了 4 年,在 Cloudflare 工作了 4 年半。

身边的牛人,欣赏、学习与超越

经常有人问我,崇拜技术界哪些大牛?我不喜欢“崇拜”这个词,因为我并不想去崇拜任何人,崇拜本身就是非理性的。欣赏的牛人倒是非常多,我把他们当作老师想尽量从他们那儿多学习一些精华,然后超越他们。随便举几位老师作为例子吧。

高三时,我非常欣赏 Perl 的祖师爷 Larry Wall 老师。和其他过程式语言相比,Perl 在风格和性质上都展现了独特的一面,因为 Larry 把语言学和哲学的思想也融入了 Perl 当中。我喜欢 Perl 展现出的文化和哲学,直到今天,它依然是我在编程世界的“母语”。

2012 年初,我着迷于 Brendan Gregg 老师在动态追踪领域的开创性工作,就精读了很多他的技术博客文章,也买了他的书来阅读。到美国以后,终于有机会在 Cloudflare 的全球网络中实践了他的很多方法和思想,快速定位了不计其数的线上“诡异问题”,有时甚至还有意外的发现。基于 Brendan 的工作,我也做了进一步地探索和创新,在一些方面还实现了超越,比如把火焰图技术延展到了内存泄漏检测和 off-CPU 时间分析等全新的维度。Brendan 在他的一次技术分享中,还专门用一张幻灯片介绍了我在这个领域的工作。

说明:Brendan Gregg,Netflix 资深性能架构师,著名性能调优专家,著有 Systems Performance: Enterprise and the Cloud(中文版《性能之巅:洞悉系统、企业与云计算》,电子工业出版社)。

最近几年,我也非常欣赏 LuaJIT 的作者 Mike Pall。针对 Lua 编程语言的 Just-in-Time 编译器——LuaJIT,在设计方面十分精巧,精巧到我都开始怀疑他究竟是不是人类(笑)。和 Mike 的邮件沟通给我很多启发,所以每次收到邮件后我都会反复研读每一句文字,生怕遗漏重要的提示。有时候,Mike 甚至会推荐他认为不错的论文给我参考。

代码之外,阅读、游泳与漫步

除了写代码,我喜欢读书,包括计算机科学、技术、数学,还有佛教研究方面的。在湾区这几年,我很喜欢在山林湖泊中漫步,思考一些艰深却有趣的技术问题。对我来说,这是一种很大的享受。此外,几乎每天都会去游泳,晚上会修习佛教早期的经典禅法,以清净内心获得奇妙的宁静和喜悦。在我看来,最本初的佛学其实是一门哲学,这与后世在中国传播的大乘佛教有着极大的差别,后者真的是一门宗教,是神学了(当然,慧能之后的禅宗倒是有很多相似之处)。

湾区的生活,非常接近我理想中的“田园生活”。我对“田园生活”的愿景起源于初中语文课本里的一篇散文,题目是《钓胜于鱼》。文中讲一位美国大学的老教授经常乘着一条小船,在湖光山色中一边钓鱼一边研究学术问题。钓上来的鱼又经常被他放回湖中。从少年时代起,这样的生活就根植于我心中,成为我理想的生活和工作状态。

OpenResty,机器编程革命“魂器”

OpenResty 是一个开源的 Web 平台,用于开发高性能和高动态的 Web 网关或者 Web 应用。OpenResty 最早是为了支持全网搜索引擎周边的相关搜索的 API 接口,后来我们基于 Nginx 和 LuaJIT 重写了 OpenResty,用于支持淘宝量子统计这款产品的所有数据 API,再后来,我加入美国的 CDN 公司 Cloudflare,使用 OpenResty 驱动 Cloudflare 全球 CDN 网络的动态 http 和 https 代理系统。

从出生的第一天起,OpenResty 就是开源的。这些年来,OpenResty 社区尝试把它用于各种不同的业务场景,有些场景甚至是我们完全无法想象的。比如有的公司使用它构建分布式网络存储系统的前端和后端(比如网盘应用);有的用它来构建完整的 Web 应用,像电商平台的商品详情页的生成和大型体育赛事的 Web 管理系统;也有的公司基于它构建大型的互联网广告平台,或者更复杂的 Web API 管理系统;还有的公司拿它来驱动小流量调度的硬件盒子,或者驱动家居陪伴型机器人;当然,更多的还是用于实现那些流量非常庞大的 Web API。似乎和流量相关的工作都有机会用到 OpenResty,我们也有用户使用完全基于 OpenResty 的权威 DNS 服务器

OpenResty 的优势在于小巧灵活、高性动态。基于 Nginx 事件模型和 Lua 的协程,我们实现了基于 I/O多路复用的高效 I/O 调度器,引入了“轻量级线程”和“协程 socket“(又称cosocket)等强大的抽象。Lua 的动态性使得代码在请求和连接级别的按需加载和热替换、热卸载变得非常容易和安全。这种能力在动态 CDN 场景下显得尤为关键,因为那里经常需要处理几十万乃至上百万不同站点的配置,而且这些配置可能一直都处于动态变化中,需要很高的生效速度,即使是全球网络的规模也是一样。

我们正在开发中的 OpenResty 新版本将包含很多重要的新功能,比如新建的后端连接遇到连接池满了的状况会自动排队和等待 ,协程 socket 在 Lua 级别主动进行listen() 和 accept() 的功能,在 Lua 中以非阻塞管道方式与新建的其他系统命令的子进程的标准输入输出设备进行高效通信。另外,在性能方面,Lua 处理程序的固有开销会显著下降,最简单的 hello world 接口在整体性能上会有百分之几十的提升。

我对于 OpenResty 一直有着宏伟的愿景:希望 OpenResty 未来能在工业界、互联网行业引领“机器编程”革命。人类只需要向机器输入行业知识和意图,机器就能自己编写高效可靠的实现代码,自行测试,进而生成人类可读的文档,最后毫无差错地布署在大规模的计算机系统上。就像现在的制造业里,机器人流水线大批取代工人一样,未来的程序员也可以从业务编码中解放出来,去做更有趣、更富创造性的工作

用户给予动力,不断推进 OpenResty

OpenResty 的发展比较迅速,动力来自 OpenResty 的广大用户。这其中既包括我之前的雇主,也包括开源社区的广大个人用户和企业用户。我曾经收到用户的电子邮件,专门为我在 OpenResty 项目上的工作表示感谢;也经常收到中国和海外用户的捐款,也许大部分的捐款并不多,但每次都让我心里暖暖的。每年的 OpenResty 大会上,我都有机会见到OpenResty 的用户,还有社区贡献者和开发者。大家的分享激励我去不断地开发新玩法和新功能。OpenResty 社区就像一个温暖的大家庭,世界范围的大家庭。广泛连接产生的幸福感和大学时每天泡在 #perl 6 IRC 聊天频道的感受很类似,只不过我成了曾经 IRC 频道里的“教主”角色!

最近两年,我们在香港专门成立了一家非盈利机构——OpenResty 软件基金会,负责接收捐款处理、OpenResty 大会支持,以及社区贡献者和开发者的奖励工作。OpenResty 软件基金会和 OpenResty Inc 商业公司是平行的关系,彼此独立运作。

商业级别技术支持和解决方案,成立 OpenResty Inc

我对 OpenResty 一直都抱有很高的期望。如果一直为其他公司工作,出卖时间的话,我就不能完全专注于 OpenResty 蓝图的实现。虽然之前的几位老板都很支持我在 OpenResty 上的工作,但毕竟拿人工资,还是要优先保证雇主的业务需求,这是基本的职业操守。

另外,随着 OpenResty 渗透到越来越多的公司和行业,社区却无力提供商业级别的技术支持和理想的解决方案。这也是开源项目运作上普遍存在的局限。

在淘宝工作的时候,我曾成功地实践了一种构造复杂业务软件系统的方式,即教机器写程序的方式,极大提高了复杂业务系统的构造速度,同时改善了系统在可理解性和运行效率方面的质量。所以,一直以来我都想着能有机会在工业界推广这种“机器编程”的革命。显然,教机器写程序的灵感源自我高中时教机器解高考题的有趣经历。这些经历又以我们不曾意料到的方式启发、推进成长。

于是 2016 年的一个晚上,我突然有了要把 OpenResty 商业化的想法,借助商业的力量召集 OpenResty 开源社区的志同道合者组建一个属于我们自己的团队。当然,OpenResty 的开源性是绝对不会变的。公司主要基于 OpenResty 构造上层的商业产品和商业解决方案,面向需求较高、挑战较大的企业用户。虽然商业版的 OpenResty 可能会有一些开源版所不具有的高级功能,但随着技术的不断创新,也会有越来越多的商业版特性被陆续移植到开源版中来,供全世界自由享用。

OpenResty Inc 的定位是一家面向企业的软件服务公司,希望探索未来 Web 系统构建和优化的新方式。我们主要销售企业级的服务器端软件和服务,为企业客户提供基于 OpenResty 和 Linux 的技术解决方案,借助“机器编程”的全新思路和方法,OpenResty Inc 极大地提高了复杂应用软件的开发速度和质量。互联网行业的工作经历让我清楚地认识到传统的软件工程方式已经越来越不能满足日益增长的复杂业务软件系统的需求。让机器来自动处理业务软件的复杂性,才是出路

“机器编程”是一个庞大的世界,我们目前的入手点选得比较小:使用“机器编程”的方式构造和销售高度灵活的分布式流量管理软件——OpenResty Edge。我们目前的商业客户有较大规模的 CDN 厂商,也有自建 CDN 的大型网站,还有把我们的软件用于网站流量入口,即跑在 CDN 网络的后面,把流量分发到后端各个不同的业务线系统。我们在产品中提供了类似文档说明书的“小语言”方便客户直接用业务语言,而不是编程语言,来表达各种复杂的业务需求和业务逻辑,然后我们的产品会自动生成各种不同类型的高度优化的代码,运行在较大的集群网络之上。

我们公司今年也计划推出分布式的动态追踪平台,叫做 OpenResty Trace,可以对大规模的分布式互联网系统进行各种有趣的性能分析和 Bug 追踪,而无需应用系统的任何配合,也不用下线或重启任何在线服务。相当于给在线软件系统拍活体 X 光片,或者核磁共振片,可以随时随地看到从操作系统内核到应用软件的脚本语言代码的方方面面,把整个软件栈作为一个随时间动态变化的整体来看待。自然地,这里也会大量用到“机器编程”和“机器推理”的方法和技术。

创业难题之多少

创业过程中的困难不少。首先是角色上的巨大转变,我从一个雇员变成了雇主,从一个打工者变成了一个老板。这在思维方式和做事方式上,都需要进行非常大的调整。我还需要学习很多不曾接触过的东西,比如融资、公司股权结构、公司财务、税务、法务、知识产权、销售与商务,等等。

其次,OpenResty Inc 从成立起就是一家“跨国公司”,跨越了中美两个国家,所以会涉及资金的跨境流动、知识产权的地域性设置与分配、不同国家的税法要求等很多方面的问题。

再次,虽然我们在美国湾区和珠海各有一间办公室,但大部分员工还是远程工作的。如何让团队紧密协作和高效运作,就成了一个较大的挑战。反过来讲,这对于我们也是一大优势,可以吸收世界上任意地点的人才加入团队,而不用担心新员工的搬迁和移民问题。另外,远程工作的巨大自由度也可以吸引到那些喜欢有独立工作空间的黑客。

最后这个小主题是个特别版块,我们邀请春哥对初学编程的朋友们,讲几句掏心窝子的话。

勇敢地走自己的路

对初学编程的朋友们,我只想鼓励大家勇敢地走自己的路!我相信每个人都有最适合自己的成长道路,而主流的教育和培训总想着趋同化,流程化,我最反感这种学习和教育。就该不拘一格,自己认准的路就值得坚持。主流的技术和思想总在快速变化中,像赶时髦那般一味地追逐是没有意义的。希望大家能不忘初心,始终保护好最初对编程的好奇和兴趣。

如果时光倒流,我能回到最初学编程的岁月,我希望自己能及早地给我所有的机器都安装上定时强制休息软件。另外,能早点做到经常去游泳,这样今天的我就不会有程序员的那些个职业病(比如脖子疼)。另外,我希望高中时的我能少花些时间在琢磨某些大软件厂商的私有技术上面,比如微软当年的 OLE、COM、COM+ 这些技术(估计今天很多年轻一代的程序员都很少听说这些名词了),能早点拥抱开源世界和开源技术。最后,希望当年的我能更加深入理论计算机科学及周边数学分支的学习和研究。进入工业界之后,我才发现这些基础理论研究才是追求“极致编程”和解决最难的工业问题的根基,而这些是最容易被普通工程师所轻视和忽略的

转载自:http://www.ituring.com.cn/article/504549

本文链接:https://helloworld.pro/post/agentzh_de_codinglife.html

-- EOF --

Comments

请在后台配置评论类型和相关的值。