midway v1.0 社区正式发布 - 阿里面向未来的全栈开发方案

简介: 双旦已过,新年将至,midwayJs 向大家献上贺礼。 之前我们向社区开放了我们的治理工具,也就是 Pandora.js 工具包,用于整个 Node.js 应用的监控和治理,我们承诺这不是结束,只是开源的开始。

main

双旦已过,新年将至,midwayJs 向大家献上贺礼。

之前我们向社区开放了我们的治理工具,也就是 Pandora.js 工具包,用于整个 Node.js 应用的监控和治理,我们承诺这不是结束,只是开源的开始。

随着内部全栈应用数的越来越多,以及阿里业务不断提升的复杂度,比如店铺,搭建以及渲染等服务,随着人员的不断调动,产品的结构,代码的层级都随着不断的调整,我们急需一个能降低代码复杂度的解决方案,帮助我们渡过人员寒冬,这就对我们内部的基础架构体系提出了不同的要求。

以往我们只需要让用户启动服务器,满足 RPC/HTTP 服务即可,而在真正的全栈领域,似乎没有太多的钻研和沉淀。对此,我们将内部使用的 midway 整体解决方案进行了一次重塑,并且在设计之初就提出未来将对外进行开源。

正巧我们的第一款 Typescript 产品 Pandora.js 开源完毕,给了我们将代码用 Typescript 重写的信心,也随着 Egg.js 社区的壮大,我们相信,在不同的领域中,一定会有不同的产品,不同的解决方案。

Midway 正式基于这些考虑,将 IoC 引入到了框架中,同时学习了 NestJs ,引入了不少自定义的装饰器,增强开发体验,也将搭配团队的其他产品,Pandora.js 和 Sandbox,将 Node.js 的开发体验朝着全新的场景发展,让用户在开发过程中享受到前所未有的愉悦感。

在这里感谢前期的 beta 测试中向我们提意见以及试用的同学,感谢大家的包容和支持,特别是 @ZQun 和 @yuu2lee4 两位的积极参与。

image-20190109121917392

下面来介绍新版本 midway 的一些特性。

  • 基于 IoC 体系业务代码进行解耦,依赖统一管理统一初始化
  • 常见的 web 场景装饰器简化业务开发
  • 支持 Egg.js 的所有插件体系,框架装饰器统一编码风格
  • 基于 Typescript ,面向接口编程的编码体验

依赖注入疑问

在一年前,我们的业务代码是重重耦合,到处初始化,实例重复,但这并不是业务同学在代码架构方面的问题,而是在不断的业务迭代,交接下,早就脱离了最初的设想,代码的设计跟不上需求的速度。

为此,我们尝试引入了依赖注入的方案。依赖注入最早听到是在 Java 端的 spring 框架,在 JS 方面,最早我们使用了 XML 做为基础的 IoC 方案,虽然解决了不少耦合和初始化的问题,也发现前端在 XML 的感受吐槽颇多。

去年 Typescript 的大力发展之后,内部的很多项目都切换了过来,经过我们的调研,除了 NestJs 进行了自研以及在 Typescript 领域比较出名的 Inversify 模块,似乎很少有现成的易于扩展的模块。

基于这些情况,我们进行了这方面的自建,一方面方便内部的扩展,能更好的在现有的体系上扩展装饰器,请求作用域等,另一方面也可以提升本身的能力,方便后续迭代。

我们产出了 injection 模块,作为我们整个框架的依赖注入基础。

如今,injection 承载起了整个 midway 体系,它将框架代码,业务代码,插件等都组合到了一起,像一个纽带在这些之间传输数据。

dep_image

通过依赖注入容器的管理,如上图非常复杂的应用也能良好的维护和运作。

想看完整大图,可以点击这里

面向装饰器开发

得益于 Typescript 对 ES6 的良好支持,提供了一种为类声明和成员添加注释和元编程语法的方法。装饰器作为TypeScript的实验性功能能够让我们在开发中简化代码。虽然是语法糖,但是带来的好处却不少。

我们拿一个简单的例子,从 Controller 一步步经过 Service/Manager 向数据库拿数据,在多层的架构体系下,以往的代码大概率需要 new 出不同的实例,并且需要绑定到路由层,这边为了方便理解,代码放到了一起。

export = (app) => {
  const home = new HomeController();
  app.get('/', home.index);
}

class HomeController extends Controller {

  reportService: IReportService;

  constructor() {
    this.reportService = new ReportService();
  }
    
  async index(ctx) {
    ctx.body = await this.reportService.getReport();
  }
}

class ReportService implements IReportService {

  reporter: IReportManager;
  
  constructor() {
    this.reporter = new ReporterManager();
  }


  async getReport(id: number) {
    return await this.reporter.get(id);
  }
}

class ReporterManager implements IReportManager {

  db;

  constructor() {
    this.initDB();
  }

  initDB() {
    // open connection
  }

  async get() {
    // return data from db;
  }
}

经过 IoC 相关的 @provide@inject 装饰器修饰以及其他 web 层的装饰器修饰过后,不仅仅只是代码量的减少,业务的代码也不再有实例化的过程。以往还需要考虑在构造器中做异步的操作,比如初始化时需要做异步连接数据库,这个时候也不再需要考虑,直接使用 @init 装饰即可。

至此,我们会更加专注于面向接口进行编程,抽象,将代码设计的时间更多的花在理解需求,解决问题上。

@provide()
@controller()
export class HomeController {

  @inject()
  reportService: IReportService;
  
  @get('/')
  async index(ctx) {
    ctx.body = await this.reportService.getReport();
  }
}

@provide()
class ReportService implements IReportService {

  @inject()
  reporter: IReportManager;
  
  async getReport(id: number) {
    return await this.reporter.get(id);
  }
}

@provide()
class ReporterManager implements IReportManager {

  @inject()
  db;

  @init()
  initDB() {
    // open connection
  }

  async get() {
    // return data from db;
  }
}

入口能力

就像上面提到的 @controller 装饰器类似,针对入口型的代码,我们在框架层面扩展了其他装饰器,比如针对计划任务形式我们提供了 @schedule 装饰器,简化用户开发的代码量。

import { schedule } from 'midway';

@schedule({
  interval: 2333, // 2.333s 间隔
  type: 'worker', // 指定某一个 worker 执行
})

export class HelloCron {
  // 定时执行的具体任务
  async exec(ctx) {
    ctx.logger.info(process.pid, 'hello');
  }
}

在下一版本中,我们将开放自定义装饰器的能力,方便更多场景的使用。

框架扩展

由于在大多数场景下,使用了装饰器已经依赖注入的写法,使得自己的业务代码,乃至三方的模块都能很好的融在一起,除了这些之外,有的同学会疑问,原本的插件,配置,上下文部分如何融入到这个体系,我们这就来解答。

在原本熟悉的体系中,只要有 app , ctx 对象就无敌了,所有的东西都可以拿。而在 midway 中,为了和 web 层进行解耦,我们隐去了这些对象,只希望业务代码和 IoC 容器打交道。

为此我们提供了 @config@plugin 装饰器用于获取不同的方法,通过这样的形式和框架进行解耦,比如在任意代码中如下使用。

@provide()
class ReportService implements IReportService {

  @config('env')
  env;

  @plugin('httpclient')
  httpclient;

  @inject()
  reporter: IReportManager;
  
  async getReport(id: number) {
    const rid = this.httpclient.request('/api/' + id);
    return await this.reporter.get(rid);
  }
}

正是这样一点点的调整,我们将整个应用的代码风格保持了到了一致,不管代码几经易手,维护的同学也能快速上手,并且继续迭代下去。

最后

正向我们在 Pandora.js 发布时说的那样,midway 也是 MidwayJs 团队长期维护的一款产品,同样不会是最后一款,前几个月,我们就计划将我们的监控平台 Sandbox 带出来回馈给社区,虽然道阻且长,任务艰辛,我们依旧在努力前行,欢迎关注。

最后,midway 的地址在这 https://github.com/midwayjs/midway/,归属在 midwayJs Group 下。欢迎走过路过点个 Star,给我们提提建议,提提代码。

Midway 官网:https://midwayjs.org/midway/

image-20190110141919113

目录
相关文章
|
运维 Kubernetes Devops
思否开源项目推介丨Choerodon:开源多云应用敏捷全链路技术平台
思否开源项目推介丨Choerodon:开源多云应用敏捷全链路技术平台
思否开源项目推介丨Choerodon:开源多云应用敏捷全链路技术平台
|
5月前
|
人工智能 安全 Linux
重磅!"OASA 安全适配认证计划"发布 牢筑龙蜥安全基石
龙蜥安全联盟将持续推动龙蜥产品与三方安全应用适配互认证、互支持工作。
|
9月前
|
机器学习/深度学习 人工智能 资源调度
隐语1.0正式发布|MVP部署体验包、资源调度框架Kuscia全新亮相!
隐语1.0正式发布|MVP部署体验包、资源调度框架Kuscia全新亮相!
221 0
|
11月前
|
IDE 前端开发 小程序
阿里 & 蚂蚁自研 IDE 研发框架 OpenSumi 正式开源
阿里 & 蚂蚁自研 IDE 研发框架 OpenSumi 正式开源
210 0
|
存储 运维 Kubernetes
从开源技术 KubeVela 谈起:云原生应用交付会怎样发展|学习笔记(三)
快速学习从开源技术 KubeVela 谈起:云原生应用交付会怎样发展。
1934 0
|
存储 运维 Kubernetes
从开源技术 KubeVela 谈起:云原生应用交付会怎样发展|学习笔记(一)
快速学习从开源技术 KubeVela 谈起:云原生应用交付会怎样发展。
1774 0
|
自然语言处理 运维 监控
阿里云中间件发展历程和开源现状 | 学习笔记
快速学习阿里云中间件发展历程和开源现状
482 1
阿里云中间件发展历程和开源现状 | 学习笔记
|
Cloud Native 开发者
云原生应用插件扩展训练营上线,帮你开始开源社区贡献者之旅!
阿里云开发者学堂联合云原生开发平台推出了云原生应用插件扩展训练营,帮你开始开源社区贡献者之旅!
云原生应用插件扩展训练营上线,帮你开始开源社区贡献者之旅!
|
存储 分布式计算 供应链
隐语:打造安全易用、社区共建的数据密态时代技术基础设施
7月4日,蚂蚁集团宣布面向全球开发者开源可信隐私计算框架“隐语”。这是蚂蚁集团经过6年多的研究打磨,推出的集成当前主流隐私计算技术的通用框架,具备安全可验证,对开发者和使用者友好易用的设计。“隐语”开源背后蚂蚁有什么思考?蚂蚁隐私计算对未来的预期是什么?蚂蚁集团副总裁兼首席技术安全官、隐语开源社区技术指导委员会主席韦韬博士在“隐语”开源发布会上做了分享。
764 0
隐语:打造安全易用、社区共建的数据密态时代技术基础设施
|
消息中间件 Cloud Native 容灾
阿里云中间件发展历程和开源现状
中间件已经发展多年,其目的主要为通过标准接口和协议解决异构网络环境下分布式应用软件互联和互操作问题。近几年,随着云原生技术的高速发展,云时代对中间件的定义又进行了扩充。2020 年由信通院牵头组织的云原生中间件白皮书对于云原生中间件又提出了 10 项新要求,主要分为底层资源、设计原则、运行时和呈现状态四个维度。阿里巴巴中间件已经有 15 年的发展历史,它与阿里业务一起成长,也是阿里巴巴云原生实践 15 年全程见证者。
阿里云中间件发展历程和开源现状