我的 20 年职业生涯:全是技术债

时间:2023-08-20 05:12:43编辑:小陈

那些年,写过的代码终将成为技术债?

1992 年,Ward Cunningham 在敏捷宣言中首次提出了“技术债”概念,主要指有意或无意地做了错误的或不理想的技术决策所累积的债务。随后,《重构》一书的作者 Martin Fowler 基于 Cunningham 的比喻,创建了一个“技术债务四象限”,包括:

鲁莽/有意:“我们没有时间去设计”;谨慎/有意:“我们必须现在交付,之后再处理因为追求速度所产生的结果”;鲁莽/无意:“什么是分层?”;谨慎/无意:“我们现在知道应该怎么做了”。

前段时间,Reddit 上有关技术债的话题再次引起程序员的广泛讨论。用户 spo81rtyOP 表示,“大多数软件的实际使用寿命也就 5 到 10 年。即便软件能幸存下来,完全由过时技术栈编写这一现实也会让它的路子变得很窄。这就是软件工程师的真实命运。”

创业公司 CTO Matt Watson 则直言,他过去 20 年的职业生涯全是技术债。

Watson 13 岁开始编程,22 岁时创办了自己的第一家科技公司 VinSolutions,实现了 3000 多万美元的 ARR,并于 2011 年以 1.5 亿美元的价格将其出售给 AutoTrader。离开 VinSolutions 后,Watson 创办了一家名为 Stackify 的公司,为软件开发人员提供应用程序监控。此外,Watson 还在菲律宾创办了离岸开发公司 Full Scale ,以支持他的 SaaS 公司。Watson 透露,Full Scale 已发展到拥有 300 多名员工。

Watson 在博客中提到,当他听到有人说“我们正在快速开发 MVP,同时最大限度地减少技术债”时,他只是笑笑,因为他知道,最终所有东西都会变成技术债。Watson 在博客中介绍了自己的 20 年职业生涯发生的变化,他悲观地表示:“如果时间足够长的话,你的所有代码都将被删除。”

Watson 的职业生涯始于 Visual Basic 6 的开发。从 1999 年到 2003 年,Watson 构建了多个不同的应用程序。后来,Watson 又花了很多时间进行经典的动态服务器页面(ASP)开发,自己也成为了在 Internet Explorer 6 和 Netscape Navigator 制作兼容网站的专家。

但在今天来看,Visual Basic、ASP、IE6 和 Netscape 都是早已被遗忘的技术了。

与此同时,在过去的 20 多年里,很多编程语言也都“失宠”了,比如 Perl、Delphi、Fortran、FoxPro、ColdFusion。也许这些古老的编程语言还存在某些应用程序中,但大多数情况下,还应用这些编程语言的公司必须要对旧的应用程序进行现代化改造,并将其淘汰。如果你用这些过时的编程语言构建程序,最终的结果可能只有重写,因为很难再找到使用这些语言的程序员了。

在 21 世纪初,人们认为 Adobe ColdFusion 是最热门的产品,但在今天呢?Ruby on Rails 也可能走上 Adobe ColdFusion 的老路,它已经失宠了,并且很难找到使用它的开发人员。曾经 Ruby on Rails 独有的东西,现在也可以在其他语言中使用了。

Watson 表示,编程语言来来往往,开发人员不希望学习工作中不需要的技能。同时,开发人员跳槽的速度也很快,他们总是希望自己的简历上有一些热门的新东西。

Watson 最初开发的一些应用程序使用了 Internet Explorer 6 中的 ActiveX 控件。当时,需要用它们来做打印和其他一些非常不安全的黑客工作。PDF 在当时并不常见,用浏览器打印简直就是一场噩梦。

Java Applets 也曾辉煌过,但它运行缓慢,并且在电脑上安装正确版本的 Java 总是一团糟。Watson 称自己永远不会忘记处理 Java 小程序网络防火墙的噩梦。“我一点也不怀念它们,幸运的是,它消失了。”

此外还有 Macromedia/Adobe Flash。当时 Flash 游戏层出不穷,许多软件都是用 ActionScript 在 Flash 中构建的。现在,一个名为 CheerpX 的产品允许使用 WebAssembly 运行旧的 Flash 应用程序。

微软曾推出一个名为 Silverlight 的 Flash 竞品。对于 C# 开发人员来说,这实际上是一个非常棒的框架。Watson 的公司也曾用 Silverlight 构建了一些非常棒的东西。不过后来,苹果在浏览器中放弃了对 Flash 和 Silverlight 的支持,从而终结了它们。

下图是十多年前,Watson 在 VinSolutions 中使用 Silverlight 构建财务计算器的屏幕截图。Silverlight 现在早已不复存在,他们用 JavaScript 重写了它,但 Watson 认为,新版本没有旧版本酷了。

2004 年还没有 iOS 和 Android,当时,Watson 曾为 Compaq PDA 编写了一个应用程序,用于跟踪汽车经销商的库存。它是用 C# 编写的,用于在 Windows CE 上运行的 .NET Compact Framework 中。

这个 PDA 有一个 100 万 像素的摄像头,只要外面是阴天,照片就会糟糕些。这个应用程序很早以前就被淘汰了,但在 2005 年时它还很前卫。

Swift 是另一个很好地说明开发工具变化速度之快的例子。苹果公司发布 Swift 后,就很难再证明用 Objective C 编写代码是合理的了。虽然在某些用例中仍然需要用 Objective C,但 Swift 明显更易于开发,并且是向前迈出的重要一步。

Watson 认为,现在任何用 Objective C 编写的应用程序都可能是技术债了。

在为构建 Web 应用程序编写了疯狂的内联脚本之后,Watson 很乐意使用新的 ASP.NET Web 表单,其服务器端控件大大简化了开发。它们的目标是让创建 Web 应用程序变得像在 Visual Basic 6 中一样简单。开发者可以在服务器端构建可重用的 UI 组件以呈现给浏览器,就像今天使用 100% 的 JavaScript 所做的那样。

WebForms 并不完美,但它是一个相当大的提升。在 Ruby on Rails 出现并普及了用于开发 Web 应用程序的 MVC(Model-View-Controller,模型-视图-控制器)框架之前,它一直运行得很好。

MVC 很快就淘汰了开发者制作的所有 Web 表单应用程序。Watson 认为,任何网页形式的东西都绝对是技术债。

不知不觉中,每种编程语言就都支持 MVC 框架了。Watson 也曾转而使用 ASP.NET MVC 做所有的新功能。它无处不在,包括 Django、Laravel、Symfony、Spring 等。

快进到今天,MVC 已经过时了。现在一切都是在 React、Angular、Vue 和其他框架中完成的。在此之前,开发者还会使用 Javascript 框架。在 Stackify 工作时,Watson 还曾使用过 Knockout,这是一个相当流行的前端框架。

但在今天,还有人记得 Knockout、Ember、Aurelia、Meteor、Backbone、Handlebars 这些框架吗?它们都“失宠”了,甚至被划分为技术债。毫无疑问,第一代前端框架输给了 React 和 Angular。

2015 年,谷歌创建了 Angular,Angular 迅速成为最受欢迎的前端框架。2016 年,Angular 进行了一次重大升级,不再向后兼容。这意味着,原始版本中的任何内容现在都是技术债。

Watson 曾在项目中使用过旧版本的 Angular,如今却成了他必须升级的主要技术债。

在 REST API 和 JSON 成为事实上的标准之前,另一种选择是 SOAP,它代表简单对象访问协议,主要由基于 XML 的 Windows 通信框架(WCF)来使用。它使得调用 Web 服务并通过自动代码生成代理类来正确调用服务变得更容易。

Watson 职业生涯中最糟糕的一个项目,就是要弄清楚如何在他的公司和另一家供应商之间通过 WCF 和 SOAP 使用安全证书。SOAP 和 WCF 的承诺令人惊叹,但随着时间的推移,维护它简直是一场噩梦。

微软决定不再支持 .NET Core 中的 WCF,REST、gRPC 和 GraphQL 现在才是首选。尽管如此,有个社区项目最终使 CoreWCF 得以继续发展。

随着时间的推移,开发者用来调用 Web 服务的技术类型已经发生了变化。旧的方式仍然有效,但大多数人可能更愿意淘汰它们。

此外还有编程语言的版本更改问题。无论是 Ruby、PHP、.NET 还是其他语言,它们通常需要改写大量的代码,甚至是完全重写。

当 .NET Core 刚发布时,它是专为在 Linux 上运行而设计的更新、更轻、更快的 .NET 版本。基本的 C# 代码都很容易移植过来,但没有人会在真实的应用程序中只使用基本代码。然而,在复杂的企业应用程序中,想要升级时可能会出现许多潜在的问题。这就成为了一笔必须解决的重大技术债。否则,开发者最终会陷在一个古老的版本中。

这些主要版本的更新,最终会成为重大的技术债项目。

Watson 在 Stackiy 遇到的最大挑战之一是卡在了旧版本的 Elasticsearch 上。有一次,它们对其工作方式进行了一些重大的更改,但这些更改并不完全向后兼容。Watson 的团队大量使用了它,于是所有的升级工作都变成了海量的技术债和升级项目。

在 Stactify 时,Watson 曾为 6 种编程语言构建了自己的跟踪/测评分析库,这项工作的工作量令人难以置信。随着 OpenTelemetry 出现,Watson 过去的这些工作变得毫无用处。既然可以使用开源的行业标准,为什么还要自己管理呢?Stackiy 正在慢慢地消除那些 Watson 帮忙构建的.NET 测评分析器。

Watson 在职业生涯早期开发的几个应用程序都已经被终止了,因为这些公司被收购了,并且决定使用完全不同的技术。

Watson 认为,随着时间的推移,你会看到你创造的几乎所有的东西都会因为各种原因而被废弃和替换,或者现在就已经都是基于旧技术的了。大多数软件的使用寿命都很有限,比你想象的要短。所有的代码最终都变成了技术债,每个人都想用更现代的方式重写,或者业务需求发生重大的变化。

诚然,在企业界,更有可能拥有似乎永远存在的内部应用程序。像铁路或大型银行这样的公司使用同样的基于大型机的软件已经有 40 年了。

Watson 预测,WebAssembly 最终会超越当今的前端开发,一个全新的世界将不断发展。

在做新项目时,大家总是希望将技术债降至最低。但 Watson 认为,不可能不产生技术债,因为根本没有十全十美的东西。随着时间的推移,今天完美的东西将来也会不完美,因此,我们需要学会与不完美共存。

而技术债的另一面是,随着时间的推移,一切都会慢慢“腐烂”——要么在升级到最新版本方面存在重大问题,要么由于更新的操作方式而最终失宠。

“一切最终都会变成技术债,否则项目就会夭折。如果幸运的话,你的代码能存活足够长的时间,从而成为别人的技术债。如果时间足够长的话,你的所有代码都将被删除。”Watson 在博文的最后说道。

Watson 的观点引发了很多开发者的讨论。赞同者认为自己过去做的很多工作最终都被取代了,辛苦编写的代码可能几年后就没有了用武之地;反对者则认为不应如此悲观,因为有些代码真的可以长青不老。

Reddit 用户、前几年刚退休的开发者 vital_chaos 提到,他这辈子在编写代码方面投入了 40 年时间,在他参与过的所有技术要素当中,只有一种至今仍在得到实际应用:

“我的团队从 1988 年起着手开发一款应用程序,直到 1994 年正式开发完成,这就是 Deltagraph。如今,它的持有公司已经在新冠疫情的冲击下倒闭。据我所知,我做过的所有其他工作最终都被取代了,或者是雇主倒闭,总之成果消失在了历史的长河中。当然,有些可能仍被使用,这个我也不敢完全确定。

所以我觉得虽然很多事情在做的时候看似无比重要,老板也总在催促要加班加点完成任务,但事后回头再看,这些辛苦编写的代码很可能几年之后就丧失了生命力!”

用户 spo81rtyOP 也非常认可 Watson 的观点:“感谢你让我确定,有这种感觉的不单是我自己。我觉得大多数软件的实际使用寿命也就 5 到 10 年。之后,因为企业倒闭或者其他原因,软件被替代的可能性会非常高。即便它能幸存下来,完全由过时技术栈编写这一现实也会让它的路子变得很窄。这就是软件工程师的真实命运。”

用户 com2kid 表示,他曾于 2008 年前后在微软工作,当时他看到过一个版权为 1994 年的头文件,里面还有作者姓名。搜索后发现,那位程序员已经在微软当上副总裁了。所以他认为,有些代码真的可以长青不老。

用户 chesterriley 则想象了一个极端可能:也许未来终有一天,人们会继续使用 100 年前就编写出来的代码。最终的大赢家可能会是 Unix 实用程序或者 TCP/IP 代码之类,又或者是某些编译器、运行时引擎或解释器。还有来自 Linux 或 Windows 等操作系统的代码。人们可能突然发现,自己修复的错误居然诞生自 100 多年前。

也有开发者认为,有些代码受到当前炒作趋势的影响很大,而 Web 开发应该就是其中最典型的代表了。考虑到过去二、三十年间 Web 开发领域发生的一系列根本性变化,这种情况也在情理之中。

用户 Otis_Inf 拥有 28 年从业经历,他表示,他还记得网景(Netscape)发布背景图像的那一天,cgi 处理程序中的 Perl 脚本也曾经是常态。无论是当年还是现在,技术的发展速度都相当惊人,开发者必须适应新的做事方式——包括提交给 cgi 处理程序的静态 html 页面,也包括异步获取部分新元素来构成视图的客户端渲染页面。

当然,也有些代码并没真正受到当今炒作的影响。有趣的是,这类代码大多集中在服务器端。虽然一直有强大的力量在“颠覆”微服务、Lambda 函数等服务构建方式,但如果忽略掉这些实现细节,那服务器的内存空间里肯定还有 db+ 服务在运行、也还有空闲周期没有利用起来。

Otis_Inf 认为,IBM DB2 仍能运行 30 年前的 SQL 代码是有原因的,这个原因就是组织仍然依赖这些功能。或者说,根本就没有足够多的人把它“重写”成新代码。那这些代码是“烂代码”或者说“技术债”吗?还是得看具体情况。你家的锤子可能也用了十来年了,它过时了吗?如果还能干活,那就没过时。只有当代码确实需要变更,但却没人处理这项工作时,它才会真正沦为“烂代码”。

“我希望看到当下诞生的新项目能始终牢记长期可维护性的重要意义,甚至把它当作一项基本设计前提。毕竟真的没多少人有能力维护陈旧软件项目。尽管地球人口仍在增加,但掌握足够技能来维护这些古早软件的开发者数量一直都跟不上。”

针对技术债问题,InfoQ 曾采访过国内一些技术从业者。

百分点 CTO 刘译璟认为,判断技术债务的重点在于“哪些事情是应该做的”,它是一个因组织而异、因项目而异、因人而异的过程,例如以下一些方面:

组织上要求做但没做的:制度、流程、规范、分享学习等;业务和技术上要求做但没有做的:功能、性能、安全、高可用、扩展、监控、辅助工具等。

如果按照软件工程环节分类,技术债务可以分为:需求分析、方案设计、架构设计(逻辑架构、功能架构、数据架构、部署架构、运行架构等等)、编码、测试、发布等。如果按照产出物类型分,可以分为:

文档类:管理过程文档、需求分析文档、设计文档、测试案例文档等;代码类:代码、脚本、规范等;软件包类:产品软件包、依赖软件、依赖资源等;环境类:开发环境、测试环境、预上线环境、生产环境等。

至于如何决定要重写还是继续维护,需要判断“继续维护的收益”和“重写的收益”哪个更大,来决定继续维护还是重写。可以综合考虑如下几方面的收益:

开源:提升现有业务收入、支持新业务的开拓;节流:节省维护人员、节省运营费用;组织:人员结构调整、组织能力培养。

债务是避免不了的,时刻判断“持有债务的价值”,当价值很低时要尽快处理。

腾讯研发总监王辉表示,如果人力、物力和工期等资源丰富,能去优化的就都可以做到极致。但通常,资源都是不丰富的,或者说是捉襟见肘的,那就要根据实际业务情况来看。腾讯一向的方式是“先抗住再优化”,项目是否真的到了非优化不可的地步,是否真的到了不优化随时都可能宕机的时候,如果先抗住了,就等业务占领了市场,站住了用户,到了项目进度慢下来之后,一些优化再开展起来,此时可以要求高可用、高性能、高并发等。

“如果项目资源允许,一些稍微过度的优化和重构,个人认为是可以被接受的,保持团队的技术热情是不错的,但如果资源不允许,就要数着钱花,判断技术债务的合理性,如何更好的还债,是否真的到了非还不可,是否真的到了影响业务发展,需要与业务优先级一起看,业务错过一个时间窗就可能永远错过,有些技术债务还可以后期再还。”王辉总结道。

参考链接:

程序员遇到祖传代码:技术债是推翻还是维护?_语言 & 开发_赵钰莹_InfoQ精选文章

上一篇:时代曲里的“严氏三杰”

下一篇:人职匹配、职业画像……毕业生求职,大数据来帮你→