ThoughtWorks 每半年都会发布一期技术雷达(最新期可在thoughtworks.com/cn/radar直接下载),对当下广受关注的百余个技术条目进行成熟度评估。在每一次发布时,我都会审视一下技术行业的各种宏观趋势,虽然这些趋势不一定会成为技术雷达的条目或主题。编制技术雷达为我们提供了一个很好的机会来深入分析软件领域的动态,以下是该领域的最新趋势:
先消费,后买单
最近几年来,我们发现业界越来越注重工具和平台的“开发人员体验”。无论是 IDE、开源库还是某种云平台,开发人员使用和采用的便捷性变得越来越重要。这是个好事情,而且通常会促进创新,将开发人员视为产品客户对企业肯定是有好处的。
与此同时,我们也发现一些问题,某种工具在一种情况下可能简单易用,而在另一种情况下可能会急转直下成为“反面教材”。例如,我们将 Jupyter Notebook 生产化放入了“暂缓”环。这是因为我们发现 Jupyter 对于分析数据以得出结论和获得洞察力而言是一款卓越的工具,但是如果你想要将 Jupyter 直接用于生产环境(而不是将代码植入到 Python 等更以生产为导向的语言中),可能会遇到巨大的麻烦。
同样,我们可以轻松地将文件放入 Amazon S3 桶,将其与简单通知服务 (SNS) 关联,然后启动 Lambda 来处理其内容,但是相关基础设施会出现混乱,导致其带来的问题可能远多于其所创造的价值。
确实,这就是“80% 规则”最新的典型示例,我们需要了解这个规则。很多工具在 80% 的使用案例中都可以提高效率,确实有用。对于接下来 10% 的使用案例,你可能仍能勉强得到想要实现的效果。但是对于最后 10% 的使用案例,你会感觉已经把自己逼到了墙角,而且不得不为之前的选择付出代价。对于这最后 10% 的使用案例,你是否能真正解决复杂性的问题?很多团队最好仔细想一想,是应该解决这个工具带来的新问题,还是另觅他法,采用其他工具。
微服务运行模式
我以前的同事 Aaron Erickson 经常说微服务是第一个真正的“云原生”架构,我们当然认为微服务是现代系统的一个合理选择。各团队应该注意微服务跟风现象,了解微服务降低开发复杂性是以提高运营复杂性为代价的。也就是说,虽然每项服务更加简化了,但是为了让各项服务协同工作,需要进行比单体架构更难的编排。
随着微服务日益盛行,我们发现利用“适当的”服务管理来运行微服务的方法越来越成熟。旧的运营方法经过重新改造,变成了新方法(例如“容错预算”)。在确定是否可以采用“谁开发,谁运行”的方法时,团队可以使用服务等级目标 (SLO) 作为一个明确的衡量标准。服务网格,例如 Istio,直接支持这些服务管理理念。 可观测性备受关注,而且很多团队都在努力确保监控工具可以充分洞察其系统的运行状况。
真正的“微服务运行模式”还会改变团队设计与职责并且带来相关组织性影响。微服务运行模式已开始涌现,但是我们认为这些模式应该建立在这样的基础上,即:首先确定一系列业务和平台功能,然后协调各个长期团队进行产品规划、构建和运行,以实现这些功能。我们强烈反对建立一体化“平台”团队,也不要指望共享业务功能能自然而然地出现并潜移默化地实现整合。
永无止境的改进
如果说“良好的”技术人员与“杰出的”技术人员有何不同(无论他们的具体专业领域是什么),那就是后者永远不会对现有的解决方案感到满意,而是会不断努力创造更好的解决方案。在业界,我们坚持不懈地改进现有设计。某个问题可能已经有一个好解决方案,但是如果有人创造了更好的解决方案,我们就会更新升级。
这方面的例子不胜枚举。例如,Taiko 是一种节点库,用于使 Chrome 浏览器实现自动化,旨在改善和简化 API。问题并不在于以前我们从未在浏览器中尝试进行过测试,而在于相应技术正在逐步改进。Deno是一种安全的服务器端 Java 和 Type 引擎,是 Node.js 的原始创造者开发的,他的初衷就是解决他在 Node.js 中发现的一些严重问题。Gremlin 是一种图遍历语言,也对其前几代产品进行了改进。Immer.js 一直在不断开拓不可变状态树的新前沿,并因此荣获了“年度最佳突破奖”。Micronaut 是一种构建微服务和无服务器应用程序的框架,在此领域带领我们向前迈出了一大步。
我们今天迈出的每一步都将引导我们在未来实现更多创新,我们之前说过这些创新将不可估量(演进架构的一个核心原则就是明知无法有效预测这些变化的情况下,仍不断构建各种系统)。
我们无法预测两年之后,也不知道这样一步步、永无止境的改进将会带来怎样的变革。
配置不堪重负
技术雷达曾经着重讨论过“配置中的编码”问题,其中似乎会发生的一种困境是某种简单的配置语言最终会不断发展,直至实现“具有图灵完备性的 XML”,这种 XML 非常难以进行测试和分析。从构建文件到模板化 Terraform 配置文件,很多情况下都会出现这个问题。最后,团队经常会发现,与使用通过强制调整而具备可编程性配置的工具相比,以可编程语言来执行测试代码会更容易。
Kief Morris 是基础设施即代码的作者,他认为根本问题在于,我们未能在配置和逻辑之间保持清晰的界限。在他看来,我们不应该测试配置文件,也不应该用可编程逻辑定义目标状态。如果执行以上任一操作,就可能会混淆界限。
Morris 建议,声明式语言应在单独的可测试组件中添加逻辑,以便于进行扩展。他说:“如果想要添加一个可以声明的新东西,可以扩展声明语言以添加一个定义,然后实施这个定义在适当语言中触发的‘方式’逻辑,并且进行测试。”
协调复杂性上升
技术行业一个普遍的趋势是总体复杂性日益上升,组件之间所需的协调也不断增加。Luigi 是数据领域的一款新工具,有助于为批处理作业构建复杂的管道。利用 Apache Airflow 可以用编程的方式编写、调度和监控工作流程。现在,各种新事物都开始进入我们的系统,例如功能即服务、工作流程、Python 进程等。
在我们最近的技术雷达会议上,Neal Ford 故意曲解 Dijkstra 的话说:“我们大幅减少了事物之间的关联,最终这些事物就会像一盘散沙,现在我们必须把它们整合起来,使之发挥作用。”
务必谨记,协调本身不是坏事情。它就像关联一样。你需要适度的协调,才能让系统有效运行并创造价值。协调是好是坏,取决于协调在应用程序中的普遍性及其覆盖范围。
业务行为扩散
组织现在面临的问题是过度依赖配置,而且协调复杂性日益提高,这意味着业界出现了一个更大的趋势:业务逻辑不再局限于小代码块,而是会扩散到整个系统中。业务逻辑已经渗透到我们配置 Kubernetes pod 和协调 lambda 函数的方式之中。Scott Shaw 指出:“有一种老理念认为,如果你有一个‘工作负载’,你可以将该工作负载移到不同的位置。如今,编写工作负载和托管工作负载分成了不同的职责,而且控制面和应用程序都清晰地分离开了。所以这种理念再也不正确了。”
更具体一点来说,业务逻辑无疑只是执行计算的东西。但是,我们还需要制定业务相关决策。如果我们要以这种方式扩展,该怎么办?我们该如何在负载下降级?这些是产品负责人应该考虑的问题,并且都属于业务逻辑,但不是传统意义上的业务逻辑。我们决定使用“业务行为”这个短语来囊括这些种类的特性。
我们对各团队的建议是,首先要认识到已经发生这种扩散。在传统架构中,重要的东西都位于业务领域层。但是现在情况已经改变,同等逻辑已经遍布于基础设施、配置、微服务和集成之中。事件驱动、无服务器功能、触发 lambda 的 S3 桶中的文件,这些因素都导致很难跟踪整个系统内的逻辑流。各团队应努力使用使整体行为更易于理解的模式,甚至可以通过降低任一系统中使用的技术的数量来实现此目的。