我们是否应当克制对新技术的追求?
毋庸讳言,程序开发是一个快速发展的行业,尤其是最近几年,从Web/移动到云、容器、DevOps、大数据、大前端、VR、区块链、人工智能,我们似乎有永远学不完的新技术;同样明显的是,程序员这个开发群体也极其热衷于追求各种更新、更酷、更强大、更优雅的技术。很难全面地评价这究竟是好事还是坏事,似乎我们已经把这当成一种不言自明的事实。
但最近,我听到了一些特别的声音,虽然它们来自不同技术背景的开发者,立场和观点也不尽相同;但这些内容似乎指向同一个结论,即:一些被认为是“老旧”的技术实际上是被低估了;而另外一些为众多开发者所追捧的新技术,它们未必真正达到如预期的那种生产力提升,并且,使用“老旧”的技术实际上可以达到同样的效果。无论如何,这些确实来自真正的一线开发者的实际经验总结。我希望你能够听一听他们的声音。
在我的职业生涯中,没有一种技能比 SQL 更有用!
作者是一个以 Postgresql 为主要产品的云服务提供商负责人。他的核心观点如下:
在我的职业生涯中,我学到了很多技能,但没有一种技能比 SQL 更有用。SQL 在我看来是最有价值的技能,
- 它对于不同的职业角色和学科来说都是有价值的;
- 一旦学会了就不需要重新再学;
- 它让你看起来像个超级英雄。一旦你掌握了它,而其他人不懂,你就显得特别强大。
我的意见:部分同意作者的说法。在这些年中,我观察到的一个有趣的趋势是:各种 NoSQL 技术开始时都标榜自己和传统 RDBMS 的不同,但随着产品的发展,他们最终还是发现自己需要 SQL (或类似的东西)。不过,我认为 SQL 也有自己的问题,那就是作为数十年前发布的技术,它没有包含关于如何分布式执行的内容,而这是从 Google 的早期论文到现在的各种数据平台一直在致力解决的。此外,目前似乎有一种令人讨厌的趋势,即随便哪个公司都声称自己在应用大数据。我相信很多小公司的数据问题是可以在 SQL 的层面得到解决的。
关于作者的观点,有一个有趣的佐证,那就是 TIOBE 的编程语言趋势报告。
从图中我们可以看到,在排名前 20 的语言各自都有不同程度的起起落落,唯有 SQL 从 2004年以后就保持了惊人的稳定,几乎没有任何浮动。为什么 SQL 能保持如此稳定的分数,TIOBE 并没有太多公开的细节可供参考,但这确实在一定程度上证明了作者的结论。从长期来看,SQL 或许应当被看作一个回报率不算突出、但非常稳定和值得信赖的投资。在投身学习纷繁复杂的各种数据技术之前,或许你应该首先了解一下这个已经存在了 50 年之久的名字:SQL。
为什么说 TypeScript 不适合大型项目?
尽管起了这样一个题目,但通读全文后你会发现,作者本人其实是很喜欢 TypeScript 的,并且在生产环境中大规模应用了 TypeScript。作者对项目结果进行了评估,最终得出结论:
我对 TypeScript 的好处、成本和不足都有了更深入的了解。我想说的是,它并不像我所希望的那么成功。除非它有很大改进,否则我不会在另一个大型项目中使用 TypeScript。
换句话说,TypeScript 并非没有价值,只是没有之前预期那么高的价值,加上引入 TypeScript 所带来的成本,使得作者认为在 TypeScript 上面的投资不太值得。
我的观点:个人比较感兴趣的是作者对项目进行评估的方法。从文中来看,作者通过开发工具、API 文档、重构、培训、招聘等方面对引入 TypeScript 的效果进行了评分。这个方法应该说是有一定参考意义的,同时,对于各个指标的分析作者也进行了详细的说明,值得一看。作者还提到了一个很有价值的观点(也可能是有争议的):TypeScript 所推重的类型安全对减少 bug 实际上没有想象的那么大,而比较传统的技术,包括单元测试和 Code View,能更全面地覆盖问题。类型安全似乎也没有多大差别。再次引用原文:
TypeScript 的支持者经常谈论类型安全的好处,但很少有证据表明类型安全会对 bug 密度产生重大影响。这个很重要,因为代码评审和 TDD 会带来很大的差异(仅在 TDD 方面就有 40% 到 80% 的差异)。将 TDD 与设计评审、规范评审和代码评审结合起来,可以看到 bug 密度降低了 90% 以上。其中的一些流程(尤其是 TDD)除了能够捕获到 TypeScript 可以捕获的 bug 之外,还能捕获到很多 TypeScript 无法捕获的 bug。
我猜测作者的结论可能会让很多 TypeScript 的拥护者有点受伤。不过我个人明确地对作者的这一观点表示赞同,即:比起各种新技术带来的改进,单元测试和代码复审理应在开发工程中发挥更大的作用。
Docker:一场令人追悔莫及的豪赌
本文的主要观点是,把所有赌注压在 Docker 上面是危险而不合理的。作者所推崇的是另一条道路:将程序部署为所谓的大型二进制文件或 uberjar(最适合这种模式的语言包括 Java、Golang 和 Clojure 等),从而在最大程度上避免依赖造成的问题。在这种场景下,不用 Docker 而使用传统的运维技术,包括 Chef、Puppet 和 Ansible, 同样能有序地管理服务器,而且避免了 Docker 带来的问题。同时,作者认为 K8S 带来的编排仍然是有积极意义的,但作者也提出了这样的疑问,即编排一定要基于容器吗?换句话说,一定要基于 Docker 吗?
原文很长,涉及的内容也相当多,可能需要反复阅读才能理解(我自己是读到第三遍才比较有把握说读懂了原文)。另外,该文是对作者前一篇文章《Why would anyone choose Docker over fat binaries?》的集中回应,因此先阅读上一篇文章有助于更好的理解文章的背景。
说实话,在读到本文之前,虽然我也知道 Docker 存在一些缺陷,但并未从系统角度去理解这些缺陷意味着什么。而本文很好的开阔了我的视角,在这个意义上,即便我并不同意作者的一些最终观点,但我仍然认为作者看待问题的角度是值得了解的。
作者提出的以下意见可以视为忠告:
最好将Docker视为一种高级优化方案。没错,它很酷且功能相当强大,但其同时也会增加系统复杂性,且只有专业的系统管理员才能够理解如何在生产中安全使用Docker并将其部署在关键性任务系统之内。
就目前来看,您需要掌握更多系统专业知识才能使用Docker。事实上,几乎所有Docker相关文章都只展示过分简单的用例,而忽略了在多主机生产系统上使用Docker所带来的复杂性挑战。这无疑给人们留下了Docker的实际生产应用非常简单易行这一极为错误的印象。
在计算机编程领域,流传着这样一句至理名言:“不成熟的优化是万恶之源”。然而,今年以来我们的大部分客户都坚持“我们必须从起步阶段就全部实现Docker化。”因此不同于传统最初最佳实践要求的建立一套工作系统、将其投入生产、最后考量Docker能否带来比较优势的作法,客户们开始盲目推动Docker的标准化开发与部署。
此外,本文还引用了另一位开发者的文章,该开发者由于在生产环境中引用 Docker 遇到了许多重大问题, 因而对 Docker 的批评更加激烈,以至于建议不要在任何严肃的场合部署 Docker。虽然观点可能有过激的嫌疑,但毕竟也是来源于一线的生产实践,并且提到了 Docker 文件系统和接口演变的一些内幕,还是颇为值得一看的。
Docker in Production: A History of Failure
写在后面
新技术肯定有新的价值,这一点毫无疑问,我也无意否定开发者求新求变的理想和追求。但在追逐新技术的同时,请不要忘了我们的“老”技术,不管你用或不用,它们就在那里。
最后,我还是想引用 《Docker:一场令人追悔莫及的豪赌》一文对旧技术的评价,因为这段文字深得我心:
无聊的好处(限制水平较高)在于,这些东西的功能相对更容易理解。而更重要的是,我们能够更轻松地了解其故障模式。……但对于闪闪发光的新技术而言,其中的未知因素要多得多,这一点非常重要。
换句话来说,已经存在了十年的软件更易于理解,而且未知因素更少。未知因素越少,运营开销越低,这绝不是坏事。