对框架的定位:Midway 基于 TypeScript 开发,结合了面向对象(OOP + Class + IoC)
与函数式(FP + Function + Hooks)
两种编程范式,并在此之上支持了 Web / 全栈 / 微服务 / RPC / Socket / Serverless 等多种场景,致力于为用户提供简单、易用、可靠的 Node.js 服务端研发体验。
- 依赖注入 IoC 实现机制,OO 机制
- 函数式实现机制(useContext 等类 React 思路),但本质上不是「函数式编程」,和严格意义上的 FP 还是有些差距。
特点思考:
- 纯 lerna 架构拆包,和 egg 的模式有所不同,小包独立发布(认知成本还是有的,特别是大量的包拍平之后)
- 纯 Typescript 输出
- Serverless 包和 Web 包独立拆解,全场景驱动做包拆分,支持一体化的模式
- 支持类似 FaaS 的使用,函数式但是依旧会混用 OO 和 decorator 的范式
- 这里对 FaaS 做了更明确的「场景界定」
- 支持 Koa 和 Express 和 Web(Midway 自己实现)的核心的切换,均做了不同层次的兼容
- 但是这不得不说是赤裸裸的维护、兼容和更新成本
- 当然还有上层的认知成本
- 支持 Websocket 等场景封装,对 Socket I/O 支持
- 增加 AOP 拦截器 的概念
拦截器和传统的 Web 中间件和装饰器都不同,是由 Midway 框架提供的能力,在执行顺序上,处于中间的位置,这个能力能对任意的 Class 方法做拦截。
- 支持 gRPC 服务
- 支持多框架 IoC 隔离,满足
IFrameworkInterface
的设计,其基类 BaseFramework 源代码可以参考 这里,实现了框架层的隔离和并存机制。- 本质上是一个 Adapter 层,连接了底层框架 & Midway 的设计
- 类 Angular 的配置注入设计,配置层声明了组件(Plugin or Component)的注入,去除了诸多 egg 层对 loader 等定义
@Configuration({
imports: [
view // 导入 ejs 组件
],
importConfigs: [
join(__dirname, 'config')
]
})
export class ContainerLifeCycle {
}
在 Egg 上跟多的约定:
- 增加 entity 和 repository 等更进一步 DDD 的概念
- OO 驱动,支持严格的 IoC 系统
- 整个 Midway 自己实现的 IoC 机制文档 讲得比较清晰了
- Midway IoC 的实现 源代码,整体围绕 Context 提供了 Inversify 子集的 IoC 能力,但阉割比较厉害,自成一套,有一定的理解成本
- 但 IoC 整体的灵活度还是不及 Inversify API 概览 这类专业 IoC 框架的设计,相对有点蹩脚,只能够在对象实例化之后注入,要在之前操作的话需要使用
@Init()
函数做处理,不过只要习惯了设定,这套依赖注入系统确实可以解决一些问题 - 个人觉得目前 IoC Token 是没有统一的 … 各种花里胡哨的写法都有,还是没有实现比较好的统一规范和约定
- 要说比较好的模式的话,还是在
constrcutor
里面做注入更自然一些,参考 VSCode ServiceInjection 的机制,整体更自然
- 整个 Midway 自己实现的 IoC 机制文档 讲得比较清晰了
- 使用装饰器 + 类的方式代替 egg 内直接对 context 对象的操作
- 比如:
@Get('/')
本质上就是劫持方法,在方法运行前 Hook 一个ctx.router.get('/')
实现一种「约定俗成」的感觉 ~ - 将大量的装饰器修饰成员类方法,提升代码的阅读清晰度
- 整体的 装饰器列表,目前 20+,理解成本较高
- 看源代码,整体实现可以再封装一个
decoratorFactory
出来,提升设计的一致性,毕竟几十个 decorator 了
- 看源代码,整体实现可以再封装一个
- 比如:
问题关注:
- 文档相对比较粗糙,没有像 egg 这么精致,毕竟维护者非全职
- Web、Koa、Serverless 等架构冗杂在一起了,整体增加了理解成本和复杂度,多纵维护,也带来较高的维护成本和稳定程度,让置信度降低
- 贡献的水准参差不齐,coverage 89% 左右
- 维度偏多,涉及面偏广
- 增大的理解的复杂度,估计这块后续要 debug 会比较困难
- 概念太多带来的认知成本问题,多多少少条款很多,特别是再罩上 egg 的概念,比如 👇 这段话,咋一看没有对 DI 系统的理解,你会一脸懵逼 😓
- 比如:组件(Component,midway 提供的概念)和插件(Plugin egg 提供的概念),两者的差异性是啥?估计框架开发者没有整理清楚都会比较懵逼 😳
- 过度复杂的功能设定,让 web 服务变得相对臃肿,整体来说,有点我本来要一根香蕉,你给我整片丛林的感觉 …
- 突然觉得 Egg 很清爽,Koa 深入灵魂 👻
- midway 自称「简单、易用」,我理解还是有一定距离的
- 不知道为什么要强行支持 web / koa / express 三种库,这会让设计变得复杂,理解成本增高,试想我想用 cookie parser,你文档里面还给我三种花里胡哨的写法,我就感觉很冗余,不靠谱 Cookies,其实这个也反射出一种设计哲学,那就是:找准定位,不要妄图兼容一切,结构和约定比覆盖范畴要更重要。
- 总体看下来,距离高质量开源项目还是有一定距离的 … 部分核心实现,比如 IoCContainer 编码风格好比业务代码,缺乏一种框架的设计感
- 对于
@Pipeline
的设计,个人无论怎样,都感觉蹩脚,将类直接以 decorator 的形式写在一个函数里面,里面理解成本和追溯实现的成本均存在,也会导致不直观性,debug 起来估计会比较蛋疼 - midway 在提倡 ioc,但其源代码却没有 follow ioc 的范式,相对死板,大量服务都是直接耦合,有失风范
问题:
- 装饰器和继承的关系应该如何解决?👉 doc
- 装饰器不应该装饰抽象类,因此底层尽量使用抽象类去解决这个问题 - 2021-11-01
- 一体化的开发模式是未来么?它主要解决什么样的问题和场景?👉 doc
- 不一定,具体的业务有具体的解法,软件工程没有银弹
- 一体化的开发模式还是适合比较轻量的,不需要前后端直接分离的场景
- Serverless 未来的空间是什么?到底什么样的业务场景适合它? 👉 doc
- 是未来,👆 的文档已经做了介绍了,简述就是:边缘服务,无状态、低密度、无长连接、要快速启动、多进程架构、密集本地 I/O 任务的
- 非常轻量的操作,比较时候 IoT 和简单的小而美的应用(其实说起来很尴尬 … 现在应用大部分都很难做到小而美 … 因此 FaaS 还是 😌 Whatever)
- 确乎需要一个 decoratorFactory 来优化 IoC 注入场景?👉 doc
- YES,大型框架一般会内置这个实现