让我们先看两段材料。
第一段出自《软件困局》[1]一书中文版译序。
软件专业的学生并没有学到在团队中如何编写便于后续维护的软件,他们在大学里完成的软件作业仅达到了课程项目的要求,却与业内软件开发的实际规模和真实复杂度完全脱节。第二段出自《黑客与画家》[2]一文。
黑客真正想做的是设计优美的软件,考核这种工作是非常困难的...大学和实验室把论文数量作为考核黑客工作的指标...这样的考核容易实施,而容易实施的考核总是首先被采用...大学和实验室不允许黑客做他们想做的事情。这听起来似乎有些匪夷所思。如今社会上炙手可热的软件行业从业人员,在大学里面竟然没有得到就业所需的能力培养?不幸的是,这就是事实,是一个软件工程专业的困局。
专业定位之殇 软件行业从业人员,通称程序员,培养此类人才的专业,直觉上对应的应当是软件工程专业。然而,这一专业在大学里面几乎天然是被歧视的。
六年前高考放榜之后,某校招生人员找到我来做招生。我仍然记得他言辞之中告诉我如果选择软件工程专业则可以保证录取,而选择计算机科学专业则有可能被调剂。时过境迁,我如今自然知道这是招生的话术,但是这两个专业在大学里的鄙视链却是真实的。
这或许是个鸡生蛋蛋生鸡解释不清的问题,但是其结果是高水平的教师和高潜力的学生涌向了计算机科学专业,而软件专业确实在各方面都矮计算机科学专业一头,如此正反馈循环,逐渐固化下来。
我无意攻击计算机科学专业,我本人即出身自该专业。然而,计算机科学并不是一个好的词汇,主要原因是根本不存在这种东西。计算机科学就像一个大杂烩,由于某些历史意外,很多不相干的领域被强行拼装在一起。这个论断及下面一段的展开承袭自《黑客与画家》的内容。
这个学科的一端是纯粹的数学家,他们自称“计算机科学家”,只是为了得到项目资助。中间部分是计算机博物学家,研究各种专门性的题目,比如数据结构的路由算法。另一端则是黑客,只想写出有趣的软件。对于黑客来说,计算机只是一种表达的媒介,就像建筑师手里的混凝土,或者画家手里的颜料。所以,在计算机科学的名下,数学家,物理学家,建筑师不得不呆在同一个系里。
黑客是软件行业创造标准和制造优美的软件的中坚力量。毫无疑问,C[3] 语言的创造者 Dennis Ritchie[4] 是黑客,Linux[5] 的创造者 Linus Torvalds[6] 是黑客,OpenResty[7] 的创造者章亦春[8]是黑客,TDengine[9] 的创造者陶建辉[10]也是黑客。
然而,我们的大学并不培养黑客,而是倾向于以培养近似数学家的学生,并以论文数量作为考核标准。《黑客与画家》对此有两段精彩的议论。
关于数学情结,
黑客是创作者,创作者不同于科学家...科学界的每一个人,暗地里都相信数学家比自己聪明。我觉得,数学家自己也相信这一点。最后的结果就是科学家往往会把自己的工作尽可能弄得看上去像数学。对于物理学这样的领域,这可能不会有太大不良影响。但是,你越往自然科学的方向发展,它就越成为一个严重的问题。关于计算理论,
黑客搞懂计算理论的必要性,与画家搞懂颜料化学成分的必要性差不多大。一般来说,在理论上,你需要知道如何计算时间复杂度和空间复杂度;如果你要写一个解析器,可能还需要知道状态机的概念;除此以外,并不需要知道特别多的理论。这些可比画家必须记住的颜料成分少很多。也可以从前段时间的热文《与恶龙斗,其乐无穷》[11]看到当代大学生为错误定位付出的代价,即相当一段时间的迷茫。
关于数学,
某课我真的听不懂啊!数学我是真的学不会啊!为什么还有人在群里 at 老师说他讲的太慢了?做个人吧!关于科研,
三月份,我从所在的实验室主动退出。原因不想展开,我在某些地方也记录过。我的同学人均在实验室打工,而我半年什么也没干。总之,我陷入了是否要做科研的迷茫之中。硅胶的宣传和教育让我觉得不做科研就是失败的,CS 同学就应该直博 PhD 做学术贡献。设计与研究 黑客的工作不是学术研究,而是软件设计。研究必须是新的,但不一定是好的;设计不一定是新的,但一定是好的。
黑客的工作往往不是从头做起,而是在现有成果的基础上做一些小小的调整,或者将已有的观点用比较新的方式组合起来。这种类型的工作很难用研究性的论文来表达。
例如,TDengine 的创始人陶建辉在《我为何要开发一个专用的物联网大数据平台,还开源它?》一文里提到时序数据库和消息队列的关系,
2008年,我创办和信,推送平台除推送之外,一个重要的模块就是消息队列。2009年,我们就研发了一个分布式高可靠、持久化存储的消息队列,每台手机需要推送的消息就放在一个队列里。消息队列与物联网的时序数据有区别吗?本质上没有。一个是非结构化的,一个是结构化的;一个是简单的进和出,但另外一个是需要有分析和计算的;两者在系统的架构设计上没有大的不同。这就是典型的黑客思路,体现出对整个领域的把握。
相反,计算机科学专业的课程里很少有这样的整体性关联分析能力的培训。例如,数据库课程就是照本宣科的记忆关系代数,背诵隔离级别。学完这门课以后,我仍然不知道一个典型的数据库管理系统包括哪些组成部分,例如 PostgreSQL[12] 的架构和核心对象;我仍然不知道在大作业上我连接数据库时采用的数据库连接协议是怎么工作的,例如 ODBC 客户端和 DBMS 的交互,查询优化与执行,以及数据传输的过程。
数据库尤其是分布式数据库的实现是软件行业成果集大成的领域。数据库的架构大致可以分成以下几个部分,
?Client?Parser?Optimizer?Execution?Transaction?Storage
这里面,语法分析、算法分析、操作系统、网络传输、并发控制、数据转换以及数据存储相关的知识都会有所体现和应用。例如 Parser 就是一个典型的语法分析应用,Optimizer 涉及了复杂的算法分析,为了获得性能和扩展性,在架构的各个部分都需要并发和网络传输相关的知识。
这些在数据库课程里都不会讲,数据库课程的核心是学习数学化的关系代数和背诵事务隔离级别。我时常想,为什么数据库课程不对着 PostgreSQL 开始讲如何设计一个数据库管理系统呢?
又例如,工业级软件往往由多个模块以及复杂的依赖所组成。分布式数据分析系统 Materialize[13] 由 SQL 语法解析器、查询优化器以及执行计划到 Dataflow 的编译器等部分所组成,同时采用了成熟的 sqlparser-rs[14] 库作为 SQL 解析器的基础。
基于第三方依赖完成工作在大学课程里是罕见的,学生往往在很长时间里都在编写单文件的玩具程序,例如典型的算法竞赛程序。由于此类程序在检验时受限的环境,往往学生每次都要自己编写底层的数据结构,并执着于处理数字或者字符串类型。
我并不否认算法在程序设计当中的作用,但是纯粹算法的研究更像是数学家或者计算机博物学家的工作,黑客对于算法应该秉持着拿来主义。例如,对于我来说,纯粹的介绍二叉树及其各种实现,是非常难以理解的。如果结合 LevelDB[15] 的实现,或者 Linux 文件系统的实现来引入和讲解,甚至实现一个小型的在查询数据结构上做出优化的对应的系统,都将是及其有趣并且受益终生的。
这方面的课程有没有好的例子呢?在我的印象里有一例,那就是编译实习。
我在上编译实习课的时候,恰好在 Perl 6 社区活跃。这门语言非常神奇的内置了自定义语法的支持,我于是拿来作为编译实习课程要求实现的编译器的基础语言,也就是说,完成了一个 Perl 6 实现的精简版 C 语言编译器项目[16]。
虽然这个项目的实现只是简单的拆分了不同的阶段,但是却是一个完整的包括接口设计与实现,数据传输以及测试覆盖的项目。虽然我并没有强烈的印象,但是我想我能不厌其烦的做软件行业基础能力的训练,能够为了实现同一类对象抽象出接口并不厌其烦的做出特定的实现,也即践行了细致的拆分与丰富的组合这个原则,应当很大程度得益于当时这个项目带来的经验。
现实世界的软件开发 在一开始的材料中,提到了软件行业开发的实际规模和真实复杂度与学校里接触的完全脱节,这是事实。
上一节的最后对单文件程序做了批判,指出抽象与交互的重要性以及测试覆盖的项目是与现实世界的软件接触的一小步。然而,现实世界的软件开发真正的复杂度远超于此。现实世界的软件开发真正的复杂度在于人,在于协作流程。
摘录《与恶龙斗,其乐无穷》一文中的一段。
好在之后在 TiKV 社区里遇见了几位很有趣的人,让我发现人生不只是学校所宣传的那几种方式,我们还有很多路可以走。在这个时间段,我坚定了做开源软件的想法,它是我的人生追求之一(但不一定是职业道路)。在之后的许多项目里,我都带入了 TiKV 社区里学到的一些习惯。开源不仅是代码开源,整个协作流程(这些代码是基于什么考虑写出来的?)、文档、工具链,都应当能直接访问。渐渐认识到了自己在学校的层面上是彻底的失败,找到失败者能享受的生活方式,大概是我比较幸运的地方。对我来说,我所代入的习惯首先是 Perl 6 社区的开放、信任与热情。虽然它终将被做成标本展览在编程语言的历史博物馆里,但是我不会忘记在 IRC 里和世界各地的人交流关于程序设计的想法的时间。我还记得函数装饰器的用途以及 AOP 这个神秘的词汇的含义是 Larry Wall 在某个深夜向我介绍的。
其次就是 Apache Flink[17] 社区带来的工业级的合作以及背后 Apache 基金会[18]成熟的做事方式。
Perl 社区毕竟是一群充满热情的散漫的黑客集中的地方,如果将他们比喻成嵇康、阮籍等竹林七贤,那么 Apache 基金会则更像是独尊儒术的董仲舒。这个基金会以帮助项目构建社区为主,其 Apache 之道[19]是开源社区不可忽视的行为准则模板。
Apache Flink 社区作为这个基金会旗下一个具体的项目社区,在协作的大纲领之下实践了具体的工作流程。
例如通过邮件列表进行异步交流,所有的决策和讨论都是公开透明的,每一个架构设计和技术决定都可以追溯和理解,如果有模糊的地方,可以直接了当的提出,并且会有了解的人给你回复。
在软件开发方面,文档和工具链齐全。在这里,我第一次知道如何构建一个 Maven 项目,如何制作一个发布版本,如何进行版本管理以及与其他人基于问题追踪工具和代码协同工具进行合作。
又例如,在工作中,我遇到过不止一次被 Git[20] 挡住开发流程的同学,倾向于把所有东西按照开发的排期揉成一团推出一个提交。然而,在 Flink 社区里我见过复杂功能的开发以及成熟的开发者是如何调和不同分支,不同补丁之间的关系的。因此就会倾向于做出更易于新人理解和上手的提交历史。
实际上,这并不是一个天赋或者过人之处。我也不止一次被 Git 挡住过开发流程,只是我见过或想出过更好的解决方式,并在此后的时间里保持和践行而已。
上面说了这么多,你可能发现了没有一个是在大学的课程里被包含到的。这就是软件工程专业困局的另一个方面,如果你想成为一个合格的工程师,那么你的能力可能大部分来自于自学。
自学的问题是什么呢?最明显的问题是,一次又一次地让每个人从头开始搞清楚这些事情是极大的浪费。我们并没有在经受训练之后站在巨人的肩膀上开展工作,我们可能要主动的在黄沙漫天的隔壁中寻找巨人的膝盖。在软件开发中,基于实验和实验结果来决定后续步骤,并在前人已经做过的工作基础上建立一个工程过程的概念几乎是完全缺失的。
后记 这篇文章起意于几个小时前看到《软件困局》中关于大学教育与现实世界的软件开发要求的脱节的评论引发的感想,以及想起来迟先生《与恶龙斗,其乐无穷》一文中的讲述。
文章的内容只是一些个人想法的碎碎念,讲述那些早已存在并被发现的问题,并未旨在提出解决问题的方法。
然而,虽然并未提出解决问题的一般性方法,在计算机科学专业或者软件工程专业仍然要依靠自学来成为合格的工程师的大环境下,还是能够提出一些或许有帮助的建议。
这里岔开一句,其实一开始我并不喜欢迟先生和他的文章,因为我总以为谦逊且坚持是应当保持的品格,出位并不是谦逊。然而,在接触过程中,虽然可能没有直接讲过几句话,却能感受到他对软件行业的热爱。热爱软件行业的人在整个行业以及学校里都是罕见的,对于这样的人我都认为是朋友。
如果回到迟先生正在迷茫的时候,或者正在风口浪尖的时候,作为朋友我可能会给他推荐《黑客与画家》以及《程序员修炼之道》[21]。这两班书都是我后悔怎么没有尽早读到的书,可以说是在理论知识上系统地补齐了学校所没有讲的软件开发的经验。这两本书常看常新,值得每一位程序员在不同的职业阶段回顾。
如果说还有一件事,那就是工程行业的目标旨在设计实现出优美的制品,在这条道路上我们经历了两次跨越。
其中第一次是从师徒制走向行业沙龙,工匠的技巧不再是师徒相传彼此互相提防,行业的交流和合作让工程行业有了跨越式的发展。如今,没有一个工程行业的从业人员会闭门造车,参加行业沙龙,相互之间借鉴和分享已经是共识。
其中第二次正在发生,即从虽然形成行业沙龙彼此借鉴和分享,但是仍然在核心技术上以专有制品的方式盈利的形式,走向开源协同,致力于提升整个软件行业并依靠专业的技术实力或服务水平获得尊重和盈利的形式。
软件行业的复杂性如此,几乎要将整个工业革命带来的以及在那之前的所有行业都数字化,都利用计算的力量来革新。这样的行业别说师徒制口口相传,就是一家大型公司乃至一个国家也未必能完全吃下这块蛋糕。只有通过开源协同的手段让最有创造力的黑客无障碍的协作,创造出一个又一个划时代的软件,才有可能完成这个历史使命。
软件工程专业的同学不必对专业困局感到无力,这个行业仍然是充满希望的行业,参与到整个开源软件革命中来,利用这股潮流的力量,或许是当下从个人的角度走出困局最好的方式。
References
【数据库|软件工程专业困局】
[1]
《软件困局》: https://book.douban.com/subject/34907888/[2]
《黑客与画家》: http://www.paulgraham.com/hp.html[3]
C: https://en.wikipedia.org/wiki/C_(programming_language)[4]
Dennis Ritchie: https://en.wikipedia.org/wiki/Dennis_Ritchie[5]
Linux: https://github.com/torvalds/linux[6]
Linus Torvalds: https://en.wikipedia.org/wiki/Linus_Torvalds[7]
OpenResty: https://github.com/openresty/openresty[8]
章亦春: https://agentzh.org/[9]
TDengine: https://github.com/taosdata/TDengine[10]
陶建辉: https://github.com/jtao1735[11]
《与恶龙斗,其乐无穷》: https://zhuanlan.zhihu.com/p/345269981[12]
PostgreSQL: https://github.com/postgres/postgres[13]
Materialize: https://github.com/MaterializeInc/materialize[14]
sqlparser-rs: https://github.com/ballista-compute/sqlparser-rs[15]
LevelDB: https://github.com/google/leveldb[16]
项目: https://github.com/tisonkun/minic[17]
Apache Flink: https://github.com/apache/flink[18]
Apache 基金会: https://www.apache.org/foundation/how-it-works.html[19]
Apache 之道: https://www.apache.org/theapacheway/index.html[20]
Git: https://git-scm.com/book/en/v2[21]
《程序员修炼之道》: https://book.douban.com/subject/35006892/推荐阅读
- #|一文带你享受数学之优美
- hive|数仓4.0笔记——数仓环境搭建——Hive on Spark
- 笔记|个人博客系统
- Core|ASP.NET Core开发-后台任务利器Hangfire使用
- dp|最近写过的dp题单(持续更新)
- 聚类|机器学习-常见聚类算法K-means,模糊c-均值,谱聚类 DBSCAN算法等
- 人工智能论文精度|论文精度 —— 2017 ACM《Globally and Locally Consistent Image Completion》
- 个人笔记|机器学习算法----聚类 (K-Means、LVQ、GMM、DBSCAN、AGNES) (学习笔记)
- 人工智能论文精度|论文精度 —— 2016 CVPR 《Context Encoders: Feature Learning by Inpainting》