对框架的定位: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 方法做拦截。 image.png

    • 支持 gRPC 服务
    • 支持多框架 IoC 隔离,满足 IFrameworkInterface 的设计,其基类 BaseFramework 源代码可以参考 这里,实现了框架层的隔离和并存机制。
      • 本质上是一个 Adapter 层,连接了底层框架 & Midway 的设计
    • 类 Angular 的配置注入设计,配置层声明了组件(Plugin or Component)的注入,去除了诸多 egg 层对 loader 等定义
      1. @Configuration({
      2. imports: [
      3. view // 导入 ejs 组件
      4. ],
      5. importConfigs: [
      6. join(__dirname, 'config')
      7. ]
      8. })
      9. export class ContainerLifeCycle {
      10. }

    在 Egg 上跟多的约定:

    • 增加 entity 和 repository 等更进一步 DDD 的概念
    • OO 驱动,支持严格的 IoC 系统
      • 整个 Midway 自己实现的 IoC 机制文档 讲得比较清晰了
        • Midway IoC 的实现 源代码,整体围绕 Context 提供了 Inversify 子集的 IoC 能力,但阉割比较厉害,自成一套,有一定的理解成本
        • 但 IoC 整体的灵活度还是不及 Inversify API 概览 这类专业 IoC 框架的设计,相对有点蹩脚,只能够在对象实例化之后注入,要在之前操作的话需要使用 @Init() 函数做处理,不过只要习惯了设定,这套依赖注入系统确实可以解决一些问题
        • 个人觉得目前 IoC Token 是没有统一的 … 各种花里胡哨的写法都有,还是没有实现比较好的统一规范和约定
        • 要说比较好的模式的话,还是在 constrcutor 里面做注入更自然一些,参考 VSCode ServiceInjection 的机制,整体更自然
    • 使用装饰器 + 类的方式代替 egg 内直接对 context 对象的操作
      • 比如:@Get('/') 本质上就是劫持方法,在方法运行前 Hook 一个 ctx.router.get('/') 实现一种「约定俗成」的感觉 ~
      • 将大量的装饰器修饰成员类方法,提升代码的阅读清晰度
      • 整体的 装饰器列表,目前 20+,理解成本较高
        • 看源代码,整体实现可以再封装一个 decoratorFactory 出来,提升设计的一致性,毕竟几十个 decorator 了

    问题关注:

    • 文档相对比较粗糙,没有像 egg 这么精致,毕竟维护者非全职
    • Web、Koa、Serverless 等架构冗杂在一起了,整体增加了理解成本和复杂度,多纵维护,也带来较高的维护成本和稳定程度,让置信度降低
      • 贡献的水准参差不齐,coverage 89% 左右
      • 维度偏多,涉及面偏广
    • 增大的理解的复杂度,估计这块后续要 debug 会比较困难
      • 概念太多带来的认知成本问题,多多少少条款很多,特别是再罩上 egg 的概念,比如 👇 这段话,咋一看没有对 DI 系统的理解,你会一脸懵逼 😓
      • 比如:组件(Component,midway 提供的概念)和插件(Plugin egg 提供的概念),两者的差异性是啥?估计框架开发者没有整理清楚都会比较懵逼 😳

    image.png

    • 过度复杂的功能设定,让 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,大型框架一般会内置这个实现