真实条件下的微前端
几年前,微前端的热度开始上升时,我注意到一句很特别的表述:
TRUE independent teams
TRUE 真的全部用了大写。
这听起来很像营销语言。但这句话一直让我在意,因为“团队真正独立”确实是一个很有分量的架构承诺:一个团队能够理解自己的系统、修改它、测试它、发布它并负责运行,而不必在每一步都等待平台里的其他团队。
我开始更深入地研究微前端以及背后的概念,也读了很多 Manfred Steyer 和 Rainer Hahnekamp 的内容。但研究得越久,“怎样把第一个 Remote 加载出来”这件事就越不重要。
真正有意思的是后面会发生什么。
这不是另一个 Getting Started
Section titled “这不是另一个 Getting Started”这个系列不是下面这种教程:
如何搭一个 Host,再接三个 Remote。
如果目标只是用 Nx 技术性地搭建微前端或 Module Federation,Nx 官方文档已经提供了相应教程。
技术初始化反而是比较简单的部分。今天的 Generator 和现成 Integration 已经替我们处理了很多过去必须手工配置的事情。
基于实践经验,我的建议是:不要太早为这件事自己造一套方案。
特殊配置当然可能合理,但它应该解决一个真实存在的问题。否则,几个看似简单的配置项很快就会长成一套小型平台,而这套平台从此也需要被版本化、测试和理解。
所以,这个系列并不从第一次成功 Build 开始。
它从 Host 已经跑起来、简单的演示幻灯片讲完之后开始。
为什么会有这个系列
Section titled “为什么会有这个系列”微前端经常通过它的技术形态来解释:Host、Remote、Module Federation、Runtime Loading、独立 Build。
这些描述的是机制,还没有回答架构问题。
在真实项目里,更重要的是另外一些问题:谁可以修改什么?哪些边界真的能够独立演进?数据、URL、UI 和业务流程分别归谁所有?某个 Remote 挂掉之后会发生什么?不同版本怎样同时运行?怎样在不每次都启动整个产品的情况下验收一个 Release?而为了获得这种自治,我们增加的基础设施和协调成本到底值不值?
很快就会发现,很多看似技术的问题,本质上是 Ownership 问题。
一个 Remote 可以单独部署,却仍然要等 Shell 团队。两个团队可以使用不同 Repository,却只能一起发布。一个系统可以包含五个 Remote,组织上却依然是一个 Monolith。
架构被分布了出去,依赖关系只是换了新的地址。
后面的文章会讨论什么
Section titled “后面的文章会讨论什么”因此,这个系列不会从一张参考架构图出发,而是从真实产品迟早必须做出的架构决策出发。
首先讨论边界本身:分布到底要解决什么问题?一个微前端可以多大?什么时候一个 Remote 是真正由团队负责的业务 Capability,什么时候它只是一个部署成本更高的组件库?
接下来,集成问题会变得更麻烦。Remote 需要共同工作,同时又应该尽可能少地了解彼此。Framework 和版本可能逐渐分叉;URL 仍然需要明确 Owner;整个界面仍然应该像一个产品;而全局技术能力也不能悄悄变成新的业务耦合。
到了认证、故障和测试,架构图已经远远不够。一个真正独立的前端,即使其他部分缺失,也必须能够合理工作;它应该可以隔离开发和验收,而不是为了测试自己先复制一整套产品环境。
然后系统进入生产。
这时问题变成不可变 Artifact、产品组合、并行版本、受控 Activation、Rollback、Observability,以及 Support 最朴素的那个问题:
这个用户刚才看到的到底是哪一个应用版本?
最后还要回到经济和组织层面。Repository Boundary、Platform Team、额外基础设施和独立 Release 都有成本。迁移本身不是目标,因此一套好的微前端策略还必须回答:什么时候应该停止继续拆分?
真实条件下的独立性
Section titled “真实条件下的独立性”贯穿这些问题的主线始终没有变化:
仅仅把代码放进独立 Remote,并不会让前端自动获得独立性。真正重要的是,团队是否能够独立理解、修改、测试、发布并运行自己的系统。
最后得到的答案不一定总是微前端。
有时共享抽象更合理;有时复制一份实现反而更便宜;有时模块化 Monolith 仍然是更好的架构;有时为了增加自治而引入的复杂度,永远不会给产品带来相应回报。
微前端既不天然优越,也不天然错误。
它是一项会产生后果的架构决策。
这个系列讨论的,就是这些后果。