“技术不重要,重要的是 AA、BB 以及 CC”

“技术不重要,重要的是 AA、BB 以及 CC”

SimpRead from zhuanlan.zhihu.com

许多程序员在自己简历上写下最好广为流传的谎言就是 “热爱技术”。你甚至可以想象,当一个刚毕业的大学本科生在简历写下这句话时,他可能连“技术” 是什么都不知道。

其实我也不知道。

我从小学开始写代码,写 VB,后来竞赛写 C,到 Python,到 Java,到 JS/TS,到 Kotlin,到一些说白了也只是玩玩的小众语言,后来又转头为了发论文回去写 C++. 你问我,我们说来说去的 “技术” 到底是个什么,我也说不出个所以然来——是编程语言的语法吗,是开源社区热衷于造的各种没有用的轮子吗,是软件架构吗,是 UML 吗,又或者是如何在其实什么都没做的情况下花一晚上熬夜做个 PPT 向老板硬吹你又整了个什么划时代的成果吗?我不知道。

哈,顺便这篇文章没有打算冒犯任何人——但换句话说,如果你能从这篇近似散文一样结构混乱的杂记中看出点什么冒犯的意思,那这篇文章大概冒犯的就是你。

尽管我到现在仍不知道 “技术” 究竟是个什么东西,但有一句话已经由来已久了——“技术不重要,重要的是 AA、BB 以及 CC”——你可以把这里的 AABBCC 换成任何东西,比如说“技术不重要,重要的是软件工程、架构、UML 那套东西”。

尽管 AABBCC 可以替换成很多东西,但我估计那些把 AABBCC 限定为软件工程及其周边的那些人大概率没在科班学过软件工程。并且不知道为什么(其实大家都知道为什么),这么说的人大多是 Java 后端程序员。

我本科就读的软件工程,从大一到大三上的必修课里大概能有七八门是软件工程专业课——说实话,它们并没有给我留下什么好的回忆,我只记得这些课大多是永无止尽的画图,UML 图,主要是类图、包图、顺序图、通信图、状态图、用例图,还有 E-R 图,还有数不清的用例分析和需求文档,数不清的系统架构设计——以及我恍惚间从软件工程短短三十多年的历史里看到的,无数研究者前辈在实验室鼓捣了几年甚至十几年的 “精心设计的适用于大规模软件应用的完美架构” 在现实中因为又复杂又折腾还不好用被最注重实用性的程序员们随手抛弃。

其实我觉得这个世界上不会有人爱画 UML 图,以至于你现在市面上能找到的有关 UML 的参考书大多成书不会晚于 2010 年,甚至 1999 年成书的《UML 精粹》还被奉为圭臬——在上世纪九十年代,UML 刚出来那会儿可是搞得轰轰烈烈的,人们误以为出现了一种通用的解法可以用来建模一切程序,后来却发现这只不过是重新发明了一套伪代码,而 UML 标准中规定的那十几种图,其实到现在也就只有类图和顺序图真正在被人使用,少数时候会用上状态图,如果你的公司很罕见地居然会用心做需求分析的话,可能还有用例图——剩下的则大多只是躺在故纸堆中无人问津的 Specification,只是一天天慢慢发霉而已——哈,Specification,一个多么无聊的词,以至于光看着这个单词都让人感到昏昏欲睡。

在 UML 最疯狂的时期,还有人搞过用 UML 生成可执行代码的烂活,最后也只是和后来许许多多类似的、基于拖拽操作生成 GUI 的各种工具一样,本质是一个逻辑——大家其实还是喜欢自己看到代码长什么样子,而不是依赖于什么工具帮我自动写好代码。其实我也一直不太看好现在各种低代码平台的思路,它们也并未超出这个思路的范畴。

在上大学之前,我就一直看到有人说,“写代码本身不是最重要的,要把眼光放宽一点,多看看设计模式、软件架构,从业务的角度看问题”。我信了,也看了很多东西,学了设计模式,又看了软件架构,本科阶段学得也尽是这些东西,甚至还看了一些运维和团队管理的东西。

只是有一天当我又打算做一个新项目时,我突然问起自己:我真的会先做好完善的用例分析、决定系统功能模块、给每个功能决定需要用哪些类关系实现,最后再对着定好的框架一行行写代码吗?

好像我从来没这么做过,我相信现在许多互联网公司也不会做得这么完整。世界就是一个巨大的草台班子,大家稍微定一下需求就直接开干了,中间大片大片的地方都是程序员的自由发挥,需求也随时会改,不可能给你事先写好几十页需求文档的机会——那改起来牵一发而动全身,工作量可太大了。

其实这种所谓的 “瀑布流开发模式” 在如今不好用也没什么特别的原因——只是当今的世界踏马的就不是这么工作的。或者说,在大量软件需要交付给可靠的工业项目或政府项目时它们可能曾经是这么工作的,但现在不是了。

其实 “写代码本身不是最重要的” 这只是一句正确的废话。荒谬一点,我甚至可以说“加减乘除不是最重要的,要把眼光放宽一点,多去学学抽象代数、范畴论之类,去把握更本质的东西”——你说得都对,但是我加减乘除都没学好,怎么去学你这个抽象代数。

写代码的是人,其次才是业务。没有人,什么业务也写不成。

而软件工程就是反人性的——它从三十多年前诞生开始就只有一个目的:消灭人,把人变成最基本的标准化工件,变成机器,变成架构建模翻译器。一个最 “软件工程” 的项目可以花八个月产出文档和设计,再花上两个星期时间以最低的工资雇佣程序员作为翻译机器一行行把文档的内容写成代码,他们不需要思考,也不需要关心自己究竟用的是什么编程语言,毕竟他们的工作只是把详细到不能再详细的文档流水线一般翻译出来——我听说日本有些外包公司就是这样干的,只是我显然不可能在日本干过,我当然也不知道是不是真这样。

我觉得这没有什么好反驳的,“工程” 向来就是这个意思——标准化和可复现性本就是工程的目的。不这么干,作为一门工程学科,你还研究什么呢?

但是哥们,这不是回到原点了吗?现在你把程序员变成了标准化的工件,但程序逻辑靠谁产出?不还是靠你那些 “架构设计人员” 吗?你这个软件项目是参与的人员变少了吗,还是成本变低了?

而且到头来,我们发现 “优雅的架构” 没有解决什么本质的问题——谷歌、微软的架构师搞了这么多年,最后代码还是堆成了屎山。保证软件鲁棒性的其实是测试,成堆成吨的测试,而不是一开始优雅的架构——随着软件规模增长,任何一开始优雅的架构都会渐渐变成垃圾的架构,而且你这个架构最开始做得越复杂,你后边改起来反而越束手束脚。而如果你一开始就按当前全世界最复杂的软件作为应用场景去设计架构,以期望之后这个软件能变得足够“Scalable”,你只会得到一个一开始连代码都写不顺手的破烂东西,新来的程序员看了三天文档就告诉你这么复杂的东西根本没法干,老员工也被这傻逼东西给逼走了,觉得你简直是异想天开。

不知道大家有没有听说过 SOAP——早期搞互联网的程序员可能比较熟悉。在 REST 被广为使用之前,人们一度使用 XML 作为网络通信的载体——XML 真好啊!可以适应任何复杂的数据,可扩展性好,又可以自描述,你还可以用 XML 自己编写 XSLT 用来处理 XML!XML 一搞出来,软件体系结构界的各位研究者就开始蠢蠢欲动,大家都想着发明一个新架构来 “大一统” 软件通信中可能遇到的所有情况——“所有情况”,听上去太诱人了,搞研究的没有不想着搞一个大一统的东西把前人所有的研究成果汇总到一起的,搞体系结构的这些人当然不例外。

于是 1998 年,微软的一批人搞出了 SOAP 作为一种网络通信协议——它用 XML 描述,在 HTTP 的基础上甚至还封装了一层(其实还支持 SMTP,但通常不会有人用),包含标头、Body 和错误信息。通常 SOAP 还和 WSDL、XSD 和 UDDI 等概念放在一起——在这套逻辑中,有一个用 XML 描述的 WSDL(Web Service Description Language,Web 服务描述语言),你需要用 WSDL 描述一个 Web 服务的输入输出 URL 等信息,其中需要包含 XSD(XML Schema Definition)用来描述请求和响应体的类型,然后将其注册到 UDDI(Universal Description, Discovery and Integration,通用描述、发现与集成)注册中心去,然后服务消费者可以从服务注册中心中查询自己需要的服务、得到 WSDL 定义并去消费它们——这其中的通信就全部使用 SOAP.

我从没用过 SOAP,但是它在教科书上占了非常多的章节,我不得不背下许多有关它的描述、以及 UDDI 这些和 SOAP 协议紧密关的东西,以求考试中获得高分。说实话,我从没觉得 SOAP 对我哪怕有一丝吸引力,至少我肯定不会在生产中考虑它——其实从架构角度来看,SOAP 和其周边生态看着还是挺有意思的,只是现在看来,几乎所有程序员都会觉得这只是白白增加软件复杂度。其实像 UDDI 这种东西,也未尝没有可取之处,现在一些项目后端暴露一个 Swagger 出去,前端拿 OpenAPI Definition 用代码生成器生成 TypeScript 类型定义,其实就是个低配和灵活一些的 UDDI.

结果到最后,人们发现自己不光不需要 UDDI,也不需要在网络中用 SOAP 传输复杂 object——原来大家在网络上只需要传输 struct,还是没有指针的那种。结果一看,连 JSON 这种花五分钟就能解释完全部 Specification 的东西都足够了,于是大家纷纷用起了 REST.

软件开发归根结底是人在开发,而不是架构师或别的什么。于是 2001 年,大家对这些对实际业务能起到的指导作用有限但又凭空增加了大量复杂度的脑弹玩意儿忍无可忍,提出了 “敏捷开发” 的概念——“敏捷开发”其实只是个象征,一个旗帜,代表着我们需要打破过去十年间一切凭空增加复杂度的东西,所以它需要反对一切,强调开发者自己,拥抱变化与沟通,而不是十几个文件加起来有好几百页的文档,不是先统计好一切需求、设计好一切功能模块的瀑布流开发。你说八九十年代软件工程研究的一切真就是纯粹的垃圾吗?也不太可能——但是我们一定要经过一个反对一切的过程才能在辩证与反思中得到合适的答案。

从 Ruby on Rails 或者更早的东西开始,我们就明显看到了软件开发从一门严谨的工程学科转向人本身的过程。Ruby on Rails 是个彻头彻尾 “反软件工程” 的东西:它强调约定大于配置、强调快速开发和开发者自身的幸福,用元编程搞了一堆隐式行为,在代码实现上又滥用 Monkey Patching、Active Record 违反单一职责原则、自动生成 RESTful 路由而不是依赖于人工为每个路由单独配置。可是这些指责都抵不过一句 “我代码写着爽” 来得有用,于是 RoR 很快流行。RoR 现在已经过了它的黄金时间,但在此之后的后端框架很少有不受到 RoR 影响的,其中一个典型的例子就是 Laravel,以及 Django,还有后来的 Phoenix 这些。连 Java 这种受到九十到零零年代软件工程极大影响的语言,其 Spring 生态这些年也受 “以程序员自身为中心” 这种思潮影响,在有意识地去配置化、去 XML 化。

很多人要说这是开历史倒车了——怎么倒来倒去最后还是回归原点了。其实不能这么说,毕竟我们要先经历过一个错误的方向,才能知道它到底有什么问题,为什么不是最正确的那个方向。人类的进步就是个不断试错的过程,其实进化本身也是,技术的发展自然也是。

所以为什么我偏偏要拉出 “技术不重要,重要的是 AA、BB 以及 CC” 这种论点,并写这么多来反对这个观点?因为技术不可能不重要——尽管我们现在甚至都不知道 “技术” 的定义是什么,但 “更重要” 的肯定不会是后面的 AABBCC. 软件开发这行,我们会经常提及的那些东西没有不重要的,技术重要、编程语言重要、代码规范重要,连我好像大批特批的软件架构其实也很重要——有经验的架构师至少能在一个范围内增强代码的可维护性,只不过到了上限之外就无能为力了。

而技术——尽管压根就没有对它的规范定义,但我这里就假设它泛指与我们编写代码技能自身有关的大多数东西——更是格外重要,因为它最贴近真实软件开发的过程,贴近人的部分。编写一个好的软件当然需要好的技术——不然呢?靠好的文档和架构?那不过是把 “技术负担” 折腾地转移到更不直觉化的方面去而已,复杂度本身没有降低。

说真的,这些年看过来,对于此类论点以及诸多变种我实在是看得有些难受了。他们往往接触到了一个此前不太明白的、全新的领域,有了些似是而非的感悟,然后自然地以为自己找到了 “更重要” 的东西。这本身从动机来说没什么可批评的,但问题在于你不能要捧个什么东西就直接说另一个你赖以傍身的东西不重要——这都可以说是有点反智的。这个世界上不存在一步登天的捷径,至少编程这行我没有看到,你提高自身能力的唯一办法就是把所有这些重要的东西一步步积累,然后你自己才能成为一个 “重要” 的人。

如果硬要找例外,这个 “技术不重要” 大概也只能在以下场景成立:“技术不重要,重要的是如何打好人际关系、如何处理同事协作、如何带领团队”这话可能有些用词不当,但道理是成立的——很少有大型软件是一个人的功劳,除了人自身的能力,人之间的关系自然也很重要,并且对于一些已经脱离底层码农的管理层来说大概更加重要,毕竟他们整天的任务实际上就是处理人之间的问题,而不再是集中于代码本身了。只是实话说,这也不能算一句对的话——人自身的能力和人之间的关系分明就是两个不同的事情,把它们俩放在这样一个踩一捧一的句子里,本身也算不得合适。

当我第一次真正接触编程时,我就喜欢上了它——因为我觉得编程是有趣的。它就像作家写作、画家画画,是一件创造性的工作,是把脑海中的想法化为现实的工作。所以当我后来看到 Paul Graham 说 “我觉得黑客与画家最为相似” 时,我感觉这是理所当然的——如果我不觉得编程是一件像绘画一样的创造性工作,我怎么会喜欢它呢?难道有人会喜欢上在流水线上拧螺丝吗?

同样的,我觉得编程语言也很重要——有些人会说 “编程语言不重要,它只是工具,重要的是你如何去实现功能” 这话在他们的角度下在一些场景里也许没什么问题,只是因为他们在某个语境里想强调一些更重要的“技能”。可是光拎出这句话来看——工具怎么可能不重要呢?你拿锯子和角磨机干活那能是一样的效率吗?拿画家举例子,画笔和颜料当然也是重要的——一幅好的画可以不用优秀的画笔和颜料画出来,但好的画大多是用优秀的画笔和颜料画出来的。好的工具至少也是你完成创作的一个充分不必要条件——编程语言当然也很重要,好的编程语言能让我更好更流畅地实现自己的想法,就像我考试时换了一只出水更流畅不渗墨的新水笔一样。

我从小学开始拿 Scratch 之类的东西折腾过各种小游戏,到初中拿 VB 做过不少工具软件,大学里则是 Python、Java 和 JS/TS. 现在看来,它们大多就是垃圾,尤其是中小学捣鼓的那些。可是在捣鼓这些垃圾的过程里我是快乐的,我意识到我在创作一个什么东西,而且我离能够真正实现我脑海中的某样东西是那么接近。而且没有这些垃圾,我也不可能在某一天突然对缺乏规范的代码感到反胃,转而去真正思考我到底需要什么样的 Formater、Linter 和 Scanner,去编写一些真正干净、整洁与优雅的东西,并开发一些真正有意义的软件。

为什么我要突然写下这些?我自己也不清楚,而且我这篇文章也没打算真的想传达什么清晰与一致的观点。只是我想描述一些我看到的、我体会到的东西,然后杂乱无章地写在一起,也许不真的是给什么人看的,或许只是作为一种发泄与倾诉而已。

我们总是向往更 “本质” 的东西。我们看到一些东西,体悟一些东西,总结一些东西,然后以为自己找到了某种普遍规律,我们误以为那些是更值得投入的东西,那些是更 “本质” 的东西。我们从小被告知要学会“透过现象看本质”——可是既然本质要通过现象发现,难道现象就不重要吗?没有现象,何来本质?

我们许多人似乎陷入了一个死胡同——追寻了很久 “通往专家的道路”,追寻了很久“什么是更本质的东西”,追寻“技术” 之外的 AABBCC,试图发现事物背后的规律——可它们大多不是 “追寻” 来的,而是经验堆积下加上一些机缘巧合的灵感得到的自然结果。他人的见解可以作为很好的参考,但那并不是你自己的路。

你是你自己,是一个完整与独立的人,是一个创造者。而与你相伴最久,并且未来还会更久的,就是你手边那些最容易触及的东西——不是 AA,不是 BB,也不是 CC.

Report Page