Ранее мы открыли для сообщества наш диспетчер процессов, набор инструментов Pandora.js для мониторинга и управления всем жизненным циклом приложения Node.js. И мы обещали, что это не конец.

Столкнувшись с увеличением количества приложений с полным стеком и растущей сложностью бизнеса Alibaba, например, для украшения интернет-магазина, создания страниц и рендеринга страниц. С постоянным статусом, когда программисты приходят и уходят, изменением структуры продуктов, постоянными корректировками слоев кода, нам срочно нужно решение, которое может уменьшить сложность кода, что предъявляет различные требования к нашей внутренней системе инфраструктуры.

Раньше нам нужно было позволить пользователю запускать сервер и работать с протоколом RPC/HTTP [1]. Но кажется, что не хватает практики и размышлений для настоящей full-stack разработки. Поэтому мы полностью переработали решение MidwayJS и с самого начала предложили открыть исходный код сообществу.

С практикой Pandora.js, которая использует TypeScript, мы получили уверенность в том, что перепишем Midway Framework с помощью TypeScript. В то же время, с ростом сообщества Egg.js, мы верим, что для разных сцен будут специальные способы.

Исходя из этих соображений, Midway представила IoC и пользовательский декоратор, который вдохновил NestJ на улучшенный опыт разработки,

и решил сотрудничать с другими продуктами, такими как Pandora.js и Sandbox, чтобы изменить опыт разработки Node.js и получить удовольствие от кодирования.

Я хотел бы поблагодарить участников, которые давали коммиты и предложения во время предыдущего бета-тестирования. Спасибо за вашу открытость и поддержку, особенно активным участникам @ZQun и @yuu2lee4.

Вот некоторые особенности новой версии Midway.

  • Разделение бизнес-кода и унифицированное управление и инициализация зависимостей с помощью механизмов IoC.
  • Декоратор, который может упростить разработку для обычной веб-сцены.
  • Поддержка всех механизмов плагинов Egg.js с единым стилем кодирования декоратором фреймворка.
  • Опыт интерфейсно-ориентированного программирования на основе TypeScript.

Внедрить зависимость

Год назад наша бизнес-логика была сильно связана, классы были инициализированы везде и полны повторяющихся экземпляров. Но проблема не в том, что человек, который пишет эту бизнес-логику, сделал плохую архитектуру. На самом деле, из-за постоянных постоянных итераций мы испортили первоначальную идею. Выяснилось, что мы обнаружили, что наш дизайн кода не соответствует постоянно растущему спросу.

Поэтому мы пытаемся внедрить схему внедрения зависимостей. Внедрение зависимостей впервые было услышано в Spring Framework Java. Что касается JS, мы использовали XML в качестве основы решения IoC в первой версии. Несмотря на то, что это решило многие проблемы связывания и инициализации, мы получили жалобу от разработчиков внешнего интерфейса на плохое отношение к XML.

После роста Typescript в прошлом году многие локальные проекты были опробованы в продакшене. И в нашем исследовании, похоже, было мало продуктов с высокой расширяемостью, кроме NestJ и знаменитого Inversify.

Поэтому мы проделали большую работу по этому поводу. С одной стороны, делайте больше работы над расширяемостью, которая могла бы поддерживать текущий спрос с помощью декораторов, requestContext и т. д. С другой стороны, улучшайте структуру фреймворка и удобство для прогрессивных итераций.

Мы опубликовали библиотеку с именем injection в качестве основы для внедрения зависимостей для фреймворка.

Теперь injection поддерживает всю систему Midway, которая объединяет код фреймворка, бизнес-код, плагины и многое другое, например ссылку на все данные.

Благодаря управлению контейнерами внедрения зависимостей очень сложные приложения, показанные выше, могут хорошо поддерживаться и работать.

Чтобы увидеть полную картину, вы можете нажать здесь.

Разработка, ориентированная на декораторов

Благодаря хорошей поддержке Typescript для ES6 появился новый способ аннотаций и синтаксиса метапрограммирования для объявлений и членов классов. Декоратор, экспериментальная функция TypeScript, позволяет нам упростить структуру в кодировании. Хотя это всего лишь синтаксический сахар, он приносит много пользы.

Давайте возьмем простой пример о контроллере HTTP, который шаг за шагом получает данные из базы данных службы/менеджера. В многоуровневой архитектуре вполне возможен код, который требует новых разных экземпляров, а затем связывает их в файле маршрутизатора в предыдущей версии.

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;
  }
}
​

После аннотаций @provide и @inject и других веб-декораторов IoC не только уменьшено количество строк кода, но и пропущена инициализация многих классов. И @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 interval
  type: 'worker', // use one worker to execute
})
​
export class HelloCron {
  // the schedule task to executed
  async exec(ctx) {
    ctx.logger.info(process.pid, 'hello');
  }
}

В следующей версии мы выпустим возможности пользовательских пользовательских декораторов для использования большего количества сцен.

Расширение фреймворка

В большинстве сценариев использование декораторов и метода внедрения делают бизнес-код даже сторонними модулями хорошо интегрированными.

Пользователя Egg.JS может смутить то, как исходный плагин, конфигурация, контекст и т. д. интегрированы в эту систему. Давайте поговорим об этом.

В первоначальной системе Egg объекты app и ctx полезны тем, что с их помощью можно получить все. В Midway, чтобы отделиться от веб-уровня, мы скрываем эти объекты и хотим, чтобы бизнес-код взаимодействовал только с контейнером IoC.

Поэтому мы предоставляем декораторы @config и @plugin для разделения, например:

@provide()
class ReportService implements IReportService {
​
  @config('env') // for app.config.env
  env;
​
  @plugin('httpclient') // for app.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 для сообщества.

Наконец, Github Midwayhttps://github.com/midwayjs/midway/, принадлежит MidwayJs Group. Добро пожаловать, чтобы дать нам предложения, комментарии или поддержать нас, нажав звезду.

ссылки

[1] HSF — это локальный распределенный протокол RPC в Alibaba Group.