去年某个周二,Jimmy Bogard在GitHub上推送了一条提交。第二天,全球数万个.NET项目的依赖管理器开始报警——MediatR转向了商业授权。这个用了十年的"基础设施",突然需要按开发者席位付费。
戏剧性的是,恐慌只持续了72小时。社区很快发现:那个被当成黑盒用了十年的库,拆开之后几乎全是空壳。命令分发、处理器注册、管道行为——这些被包装成"框架能力"的东西,纯手写不到50行。
![]()
被混淆的两个概念
MediatR和CQRS在.NET生态里纠缠太深,以至于很多人分不清边界。
「CQRS的核心就两句话:命令改状态,查询读数据。」原文作者用极简定义划清界限。命令有副作用,查询无副作用——除此之外全是实现细节,不需要任何库。
MediatR的流行源于一个历史巧合:它把"处理器自动发现+统一分发器+行为管道"打包成了三行配置代码。这三行代码解决了启动阶段的繁琐,却也制造了依赖幻觉——仿佛没有它,CQRS就无法运转。
授权变更撕开了一道口子。团队被迫审视:那些三行代码换来的便利,代价是放弃对抽象层的完全控制。
正方:手写实现的价值
剥离框架后的实现出奇地薄。五个接口定义全部关系:
两个标记接口ICommand和IQuery作为类型系统的锚点,让编译器强制约束命令与处理器的配对关系。三个处理器接口分别处理无返回值命令、有返回值命令、查询——泛型参数确保「错误的使用会在编译期报错,而非运行时爆炸」。
作者特意为标记接口辩护:通常这确实是反模式,但此处它们承担了两个不可替代的职责。一是为程序集扫描提供明确目标——没有ICommand,无法写出AssignableTo(typeof(ICommand<>))这样的筛选条件;二是让分发器的泛型约束具备编译期检查能力。
DI容器接管剩余工作。处理器注册、生命周期管理、依赖注入——这些本就是容器的基础设施,无需额外封装。手写代码的优势在于透明:每个抽象层的职责、数据流向、扩展点都暴露在开发者眼前,而非藏在库的源码深处。
反方:框架的隐性收益
手写派忽略了一个成本:团队共识。
MediatR的价值不仅是代码,更是「社区共同语言」。新成员入职,看到IRequestHandler立刻知道该往哪写逻辑;代码审查时,管道行为的命名和顺序有既定惯例;遇到异常,Stack Overflow上有数千个已解答的问题。
手写实现意味着重建这套共识。五个接口的命名风格、分发器的错误处理策略、横切关注点的注入方式——每个决策都需要团队内部反复对齐。对于五人以下的团队这或许轻松,五十人团队则可能成为摩擦源。
另一个隐性成本是维护责任。MediatR的管道行为、异常处理、性能优化由社区持续迭代;手写代码的同等能力,需要团队自己长期投入。授权费用本质上是把这部分成本货币化,而非消除。
判断:什么时候该拆,什么时候该留
决策锚点在于「控制需求」与「团队规模」的交叉。
需要完全控制抽象层时,手写是理性选择。比如:处理器需要跨进程边界(从内存调用改为HTTP/RPC)、管道行为需要与特定遥测系统深度集成、或者团队对性能有极端敏感的要求。这些场景下,MediatR的封装反而成为障碍——它的扩展点设计服务于通用场景,特殊需求需要绕路或 fork。
团队规模小、迭代速度快、无特殊基础设施需求时,保留框架更经济。授权成本若低于「重建共识+维护基础设施」的人力折算,付费是合理交易。但需警惕「路径依赖」:因历史惯性继续付费,而非主动评估。
一个值得观察的信号是:手写实现的核心代码(接口定义+分发器+注册逻辑)在多数项目中高度相似。社区可能出现轻量级替代方案——不是第二个MediatR,而是「可复制的50行代码模板」。这种形态既保留透明性,又降低重复决策成本。
MediatR的授权变更,最终暴露了一个被长期遮蔽的事实:CQRS作为模式,其复杂度被框架人为放大了。当开发者发现「原来我自己也能写」,对基础设施的迷信便开始瓦解。这种认知迁移的影响,可能比任何具体的技术决策都更深远。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.