本文深入剖析了 .NET 开发者对生态系统的复杂情感。一方面,他们依赖微软提供的解决方案,认为这最为稳妥;另一方面,他们又对第三方工具抱有担忧,在信任与恐惧之间挣扎。在 .NET 生态系统中,各种观点相互碰撞,有的开发者坚定地支持微软的首选方案,而有的则强调多样性和选择的重要性。
然而,文章也揭示了单一选择可能带来的局限性,以及对第三方工具长期支持和生存能力的疑虑。这让我们不禁思考,.NET 生态系统的未来应如何发展?如何平衡微软的贡献与第三方创新之间的关系,以确保 .NET 能够持续进步?这些问题值得我们深入探讨。
近日,一则名为 “Epic: Eventing Framework in .NET 9” 的 ASP.NET GitHub 话题在开发者社区引起了轩然大波,背后主要原因是微软在其 .NET 开源生态系统中展现出的强势插手态势。对于这种现象,如果放在几年前,我或许还会因此感到愤怒。但如今,这几乎已经成了微软的惯常做法 —— 对此,我也曾在我的文章中有过类似论述。无论我们怎样表达愤怒,或是展现开源社区的精神,似乎都无法撼动微软那座坚固的象牙塔。要想真正带来改变,恐怕得从改变对 Azure 的投入开始。
如果你想在 .NET 生态系统中作为开源项目或工具开发者参与进来,那么接受这样的现实或许就是入场的代价。如果你觉得微软涉足你的领域就意味着要放弃,或者这足以摧毁你的业务,那么从一开始,或许你就缺乏足够的创意、决心或热情。
微软声称他们开发这个框架主要是为了改进 Azure WebJobs,因此不会对 MassTransit、Wolverine、MediatR 等构成真正的威胁。但对此,我持怀疑态度。如果微软并不打算让第三方真正使用它,那又何必将其列为 ASP.NET 的重大工程,更何况 ASP.NET 还是生态系统中最受欢迎的框架呢?
不过,真正让我感兴趣的并不是这个帖子上开源软件生产者或微软的反应,而是 .NET 开源软件消费者的反应,这实在出乎我的意料。竟然有那么多 .NET 开发人员欢呼这些流行的第三方框架被摧毁,仿佛拥有多个、维护良好的工具成了一种需要解决的麻烦。
究竟有哪些 .NET 开发者会要求 .NET 毁掉自己的生态系统,甚至将 .NET 带回昔日竞争力不足、智力贫瘠的时代呢?
.NET 开发者的两种观点
在那个帖子中,存在两种截然不同的 .NET 开发者群体。
第一种认为供应商多样化是件好事,他们倾向于拥有多种可行的软件交付选项,这样可以根据自己的需求进行选择,从而保持生态系统的健康和竞争力。而第二种观点则相反,他们认为供应商多样化并不是好事,主张应该有一个统一的标准来指导我们的工作,包括构建复杂的事件驱动架构等任务。他们认为,只要微软支持这个单一标准,我们就不必担心其他问题 —— 因为这个标准将比其他任何选择拥有更完善的文档、更好的维护和更高的可操作性。他们建议围绕这个标准整合生态系统的其他部分。
需要明确的是,这两种观点并非同等有效、可以简单 “同意或不同意” 的。第二种开发者群体所信奉的这种信念体系,实际上限制了他们的能力和技能,相比第一种开发者显得更为不足。这种自我设限的信念,最终可能导致他们成为所谓的 “专家初学者”。
那些认为评估甚至只是拥有工具选项都是浪费时间的人,很可能并不具备构建高流量客户面向的 SaaS 应用、工业物联网、自动交易系统或其他比简单数据表单更复杂项目的能力。我之所以参与 .NET 开源软件,完全是因为我希望增加能够利用 .NET 构建这些重要系统的开发者的数量。
主张摧毁选项并不是我们应当参与的积极讨论,因为“让生态系统变得更糟、更不具竞争力,以便我无需面对选择”这种思维过于短视。尤其对于那些从未经历过 .NET Core 之前的 .NET 生态系统之弊端的开发者,或是那些“资深”开发者中未曾关注过在看似微不足道的应用程序中默默付出的人们,这一点尤为凸显。
第一类:选项寻求者
竞争是积极的,拥有多种可行的选择是有益的。微软进入事件处理领域并不会淘汰现有的解决方案,用于构建消息或事件驱动架构;实际上,这可能会增加首次尝试构建它们的 .NET 开发者的数量——这是值得欣喜的!
微软介入事件处理领域,若其影响导致开发者在构建软件时不再充分考虑其他选择,则可能产生“负面影响”。一个常见的例子是,越来越多的新手 .NET 开发者知道 Entity Framework 的工作原理,但不知道如何直接与 SQL 交互——既然 Code First EF“有效”,那他们为什么还要去寻找其他选择呢?
第一类选择者关注的是选择和自由——他们了解每个可能选项都涉及技术和风格上的权衡,并希望能够获得这些选项。选项的减少必然意味着更少的创造自由,可能无法获得真正需要的工具(这在 .NET 的早期时期就经常发生)。
我经常被问到对 Microsoft Orleans 与 Akka.NET 的看法——我通常会回答我也很高兴它们都存在,因为在 2013-2014 年,当我需要一个可行的 .NET actor 模型实现时,它们都还没有出现。Orleans 和 Akka.NET 在使用 actor 构建软件方面有不同的方法,我认为在这个领域有竞争是积极的。Orleans 的存在并没有对 Akka.NET 的采用率造成任何伤害,因为 Orleans 和 Akka.NET 之间的这些差异对这两个技术的用户都非常重要。
选择使我们在 .NET 生态系统中的工作经验对雇主和我们自己都更具经济价值——因此,选择是积极的。
第二类:恐惧者
我对一些 .NET 开发者在 https://github.com/dotnet/aspnetcore/issues/53219 上的评论感到惊讶,他们表现出对 .NET 开源项目的恐惧,因此要求微软提供官方解决方案来解决他们的问题。以下是一些例子:
“[OSS 工具] 的目的就是为了宣传其创建者。” “在这个讨论中,我看到维护者抱怨这会扼杀他们的产品,而他们那拥有十年历史却只有 1k 颗星的项目也难逃厄运。无论微软是否介入,你们的采用率依然会很低。” “你知道谁从未帮助过我吗?是开发者。那么多开发者如此敌对、保护主义、领土主义,又充满防御性,真是令人惊讶微软竟然如此主动地拥抱开源,因为我们当中有太多人充满敌意。” “.NET 仍然需要很多创新,以及历史上分离的产品线之间的统一。我想要的是一个统一的 .NET,社区中的分裂程度最小。当你可以拥有一个易于使用并在开箱即用时集成所有最佳实践的库时,就没必要有 5 个基本做同样事情的不同库。合并是好事,应该被接受,因为它可以减少 .NET 社区中的分裂,为新的创新提供更多资源。” “YouTube 效应催生了一代全新的开源项目,这些项目似乎只是为了追求精英地位而存在。一些开源项目所有者如此自私,我真不明白他们为什么要涉足这个领域。发现一些开源社区中最重要的人物也是最不友好的人物,让我深感失望。” “我一直担心 MassTransit 等工具能否长期存在。”还有诸如“我们的律师让我们选择技术栈”之类的借口,这简直就是企业版的“狗子吃了我的作业”。
.NET 开发者常因公司合规要求,需详细列出并证明每个第三方库的引入情况。对于微软的库,一般无需额外审查。然而,第三方库则必须通过许可证清理,有时还需核查作者,以确保其不来自受限制的国家。
— Ted Anderson (@TedsTechTed) 2024 年 2 月 14 日
这一问题正是 .NET Foundation 旨在明确解决的第三方 .NET 开源项目所面临的挑战之一。该基金会致力于确保所有纳入其内的项目都拥有清晰(无侵权)的知识产权和商业友好的开源许可证 —— 这两个问题恰好是非工程利益相关者所关心的焦点。值得一提的是,我们的项目 Akka.NET 正是 .NET Foundation 的成员之一。
Akka.NET 目前已被美国银行、美国联合航空公司、西门子、美国人力资源管理局、诺斯洛普・格鲁曼、戴尔、高通等众多公司应用于生产环境。我们已对其中部分公司进行了知识产权和许可证的审查,但仅限于此。即便在国防承包、司法系统、政府以及《财富》100 强等敏感领域,我也未曾见过法律部门强制规定必须使用特定库作者的情况。开放源代码的核心优势在于其透明性,你可以清楚地了解所获得的内容。如果你希望在技术供应链上做到极度警惕,你完全可以从自己的机器上克隆源代码,自行构建所需的组件。
实际上,只有软件开发者自己才会提出如此严格的库供应商规定,这也是这种说法在很大程度上站不住脚的原因:
然而,这些政策究竟是由谁制定的呢?答案是高级软件开发人员!实际上,公司律师等人通常是追随 IT/R&D 部门的领导,而非相反。
此外,将这种情况视为大公司中不可改变、固有的事实,实际上是开发人员学会了无助的一种表现。
— Aaron Stannard (@Aaronontheweb) 2024 年 2 月 14 日
我经常在我的博客上探讨 .NET 开源生态系统。我们面临的许多问题,例如开源可持续性,都是软件生态系统中普遍存在的。然而,这些评论揭示了一个 .NET 生态系统特有的问题:单一供应商主导下的单一文化,在这个案例中即微软。
这些抱怨实际上反映了部分 .NET 用户内心深处的深深忧虑:
主导因素:在面临多个选项时,若微软的选项不存在,他们可能会因技术选择不当而受到指责。因此,遵循微软制定的“标准”可以使他们免于承担个人责任。
长期来看,他们担心第三方项目无法提供持久的支持,因此认为微软的选项默认是“安全”的。
他们认为第三方技术的质量无法达到微软在该领域的产品水平。
他们将第三方开源项目的创建者视为精英主义者,并担心会遭到虐待,而微软则会对他们的需求做出迅速响应。
这些用户正在放弃自己的批判性思维,盲目地信任微软,这主要是因为流传着“选择微软从未导致人被解雇”的说法。
在其他软件生态系统中,这种情况并不常见。如果一个 Java 开发人员因为害怕使用 Confluent 的工具而要求 Oracle 推出一个官方的 Kafka 替代品,那么出于上述原因,他们可能会受到嘲笑。但在 .NET 领域,我们却因为某些原因对此予以考虑,这是我们应该停止的行为。
这是情感推理导致的技术采纳现象——人们选择站在微软这一边,并非因为他们的工具最适合工作,而是因为它提供了最强大的责任追究防火墙。“选择微软从未导致人被解雇”这句话被过度解读了。
最让人感到悲哀的是,这些被提出的关于微软“安全”的理由中,大部分甚至都不是真实的。
对于那些担心开源工具持久性的用户,他们可以问问那些在 2011 年 Silverlight 突然被取消时的用户的感受。或者问问 WPF/UWP/MAUI 用户,他们对微软在 2024 年桌面 UI 领域的产品有多大的信心。
于我之前引用的评论特别关注 MassTransit 的持久性:MassTransit 自 2007 年开始开发,而 Windows Communication Foundation (WCF) 则始于 2006 年。那么,在 2024 年,这两个框架中哪一个仍在积极维护呢?
对于这种情绪,我不得不佩服其纯粹的 “卡夫卡陷阱” (Kafkatrap)能力:
尽管存在一些缺陷和糟糕的决策,但微软对于那些感到被他人忽视或轻视的数百万开发者来说,仍然是一个积极的因素。.NET SDK 是由一些世界顶尖的工程师开发的,其文档内容庞大且详尽。微软在发布新版本时始终保持着连贯性和纪律性,并不断创新。此外,他们的外交手段也非常出色。
尽管我认为微软对产品质量的承诺是毋庸置疑的,但在这个生态系统中,只有那些极度缺乏经验的开发者才会相信,与拥有 10 万名员工、市值 2 万亿美元的公司进行接口交流,会比与一个由 3 人组成的开源项目进行接口交流更容易。微软开发的任何项目都有可能在经历 1-2 次企业重组后就消失无踪。想想那些可怜的 AppCenter 用户的遭遇吧:
哇,微软要关闭 AppCenter 了!— Simon Cropp (@SimonCropp) 2024 年 3 月 15 日
在帖子中,有用户高度赞扬了 ASP.NET 的速率限制功能,认为这体现了微软无与伦比的天才,为 .NET 开发者提供了一种便捷的功能,这种功能对于许多所谓的“门外汉”来说可能是遥不可及的,这确实令人感到惊讶。
不过,考虑到“选择困惑者”的观点:“微软默认提供的选项往往过早地让大多数 .NET 用户停止了寻找最佳选项的探索。”
然而,事实上,这位用户所称赞的 ASP.NET 速率限制 API 在大多数实际应用场景中,其“实用性”显然是不够的。
它们仅限于在进程内使用,因此,对于那些最重要的经济上有用的速率限制应用(如按租户计量收费)来说,这些功能根本无法使用。目前计划在 .NET 9 中修复此问题链接。
它们的配置十分复杂,难以理解——实际上,执行一些基于流的编程(如 Rx、TPL Dataflow、Akka.Streams)会更为简单。别问我是怎么知道的,因为我整天都在处理这些工作。
它们对背压不敏感——任意对 Web 应用程序进行速率限制是不明智的。我们应该仅在响应业务原因(如第 1 点所述)或因为共享资源(如数据库)开始变得不可用,且选择优先处理某些流量而非其他流量(这也是一项业务规则)时才应该这样做。这需要一些背压意识。目前,最接近支持此功能的 API 是令牌桶速率限制策略。
当你真正需要开始应用速率限制时,这个 API 在开箱即用的情况下,使得理解重要的副作用和流控制变得困难。我再强调一下,如果这是一个基于流的编程模型而不是基于配置的模型,那么实现起来会更容易。根据我的应用程序要求,我可以简单地开始缓冲、分批处理、减弱请求或执行其他适当的操作。然而,在这种情况下,你只能拒绝一个请求,然后在事件处理程序中可能做一些其他工作。
ASP.NET 之所以推出这个速率限制功能,主要是因为“需要”这个功能,但它在考虑实际高流量应用程序需求时显得捉襟见肘。那些一直在努力管理 ASP.NET 和其他 .NET 系统中高吞吐量流量的开发人员,比如那些在 https://github.com/ThrottlingTroll/ThrottlingTroll 中支持分布式按租户限制速率的第三方解决方案,他们在设计这些功能时会更加完善。这是因为他们的业务依赖于这些功能,而不是因为微软的产品经理将其纳入了今年的目标和关键结果文档中。.NET 团队做得不错,但他们推出和做事情的动机不同,这一点在他们的优先级中得到了体现。
在库/框架作者与用户需求的“一致性”方面,第三方开源选项通常比微软更贴近实际。许多这样的项目都是作者因为感受到真实业务需求而产生的,比如 Akka.NET 就是这样诞生的。
如果微软今年必须交付“云原生”内容,明年又必须“与 Python 在极简主义上竞争”,那并不一定符合当前框架用户的真实需求。此外,由于 .NET 团队需要支持的用户、用例、版本和群体的数量和多样性,他们必须提供满足最低公共分母的体验。这就是为什么像 ASP.NET 的速率限制这样的抽象概念,甚至是早期的IDistributedCache这样的功能,在实际应用中并不常见的原因——对于严肃的客户导向的生产用途来说,它们显得相当笨拙。
因此,这位用户在吹嘘这个功能有多好的同时,也暴露了自己在速率限制方面缺乏实际经验。这也印证了那些寻找更好选项的人的观点,即只要微软在该领域提供了某种解决方案,开发人员就会停止寻找最佳工具。这正是有人对微软构建事件解决方案提出担忧的原因所在。
战略思考与行动
对于 .NET 的开源软件,你或许无需过于关注。选择微软的官方解决方案同样无可非议。然而,在选择微软的解决方案时,有两种截然不同的动机:一是因为你确信它能满足你的需求,而另一种仅仅是因为微软推出了它。尽管这两种决策过程最终可能导向相同的结论,但前者是基于理性的推理,后者则显得较为牵强附会。
过度吹捧摧毁选项只会损及自己的长远利益,因为这样做会让人才和优秀组织疏远 .NET。下次你在/r/dotnet 上询问“为何主流互联网平台不采用 .NET?”时,请铭记,这正是因为在 .NET 的过去,构建这些平台的工具匮乏。
.NET 自跨平台以来一直在稳步发展。若你希望这种进步势头得以延续,就应当支持 .NET 生态系统中选项的扩展,而非致力于毁灭它们。
作者简介:
Aaron Stannard,Petabridge 公司的首席技术官兼创始人,致力于通过开发 Akka.NET、Phobos 等项目,让 .NET 开发人员更轻松地进行分布式编程。
原文链接: