К содержимому

go-like в сравнении с другими инструментами ​

Честное сравнение начинается с владения и ответственности, а не с таблицы галочек по числу возможностей. NestJS, Fastify, Hono, Elysia, Koa и tRPC решают разные задачи в TypeScript-стеке приложений. go-micro и go-kratos — это ориентиры из мира Go с другими решениями для транспорта и генерации кода. go-like — набор строительных блоков для TypeScript, делающий явными жизненный цикл, внутренние унарные вызовы, контракты провайдеров и композицию между runtime.

На этой странице разделены уровни доказательности:

  • Исходный код означает, что текущая рабочая копия go-like предоставляет указанное API или границу.
  • Зафиксированный внешний источник означает, что сравнение опирается на release, commit или официальную документацию, записанные в исследовательском журнале. Это не свежий benchmark и не утверждение, что незафиксированная ветка main не изменилась.
  • Заявлено означает, что в репозитории есть пример или тестовый lane. Это не означает успешный результат.
  • Пробел означает, что текущий репозиторий не доказывает обещанную совместимость.

Текущая базовая версия исходников go-like для этого трека — commit 9385dbf5b6a7d913be56a80ade359e1bf9be8675. В локальной исследовательской записи есть расхождение по commit go-micro: одна сравнительная запись называет 9d306dcfc1a912a8a9493f31fee0bb983475258d, а подробная записка по фиксированной версии изучала go-micro v6.9.0 на 3c39d17fadaa9ec21b671be4afef3e63846406e6. Считайте эти значения входными данными для повторной проверки, а не гарантией текущего состояния upstream.

Место в стеке ​

ИнструментОсновная задачаЧто обычно находится в его ответственностиЧто go-like может дополнить, но не заменить
NestJSКонвенциональный Node-фреймворк приложенияModules, providers, controllers, decorators, application context, lifecycle фреймворка, HTTP- или microservice-adapterСтруктурную границу жизненного цикла или контракт внутреннего вызова вокруг нативного приложения, если написать явный мост
FastifyNode HTTP-сервер и pipeline запросовТаблица маршрутов, hooks, plugins, encapsulation, Node listener, объекты request/replyАдаптер жизненного цикла или провайдера вокруг ресурса, которым владеет Fastify
HonoМаршрутизация и middleware на Web StandardsRoutes, middleware, sub-apps, app.fetch, выбор runtime-адаптераCore App, явный lifecycle ресурсов, внутренние Client/Transport, discovery
ElysiaТипизированный Web-фреймворк с фокусом на BunДерево маршрутов, композиция схем, decorators, hooks, Bun- или Web Standard-адаптерБлоки Core для жизненного цикла и внутренних сервисов при сохранении нативного поведения Elysia
KoaМинимальное Node-ядро middlewareЦепочка middleware и Node listener; роутер обычно внешнийЖизненный цикл и внутренние сервисные контракты без добавления ещё одного роутера
tRPCТипобезопасный слой процедурПути router/procedure, парсеры input/output, context factory, HTTP/Fetch/WS-адаптерыВладение провайдерами, политика обнаружения сервисов, явный lifecycle App
go-microGo-экосистема микросервисов и агентовGo Context, абстракции service/client/transport/registry/broker, экосистема провайдеров и дополнительная область agent/flow/MCP/A2Ago-like заимствует часть словаря, но не Go ABI, goroutine и совместимость транспортов
go-kratosGo-фреймворк для cloud-native-сервисовЖизненный цикл App, Go Context, HTTP/gRPC-транспорты, middleware, registry, config, генерация кода ProtobufКод Context-first на основе Protobuf-ES; Стандартный gRPC: четыре вида вызовов через /native
go-likeЯвные строительные блоки для TypeScript-сервисовContext, lifecycle App/Server, стандартный Fetch-край, внутренний Fetch JSON и SSE, Client/Server, Registry/Discovery/Selector, Config/Store/Cache/Broker/Health, adaptersПриложение по-прежнему владеет маршрутами фреймворка, нативными плоскостями данных, бизнес-политикой, auth и deployment

Проект не пытается выиграть сравнение «самый большой фреймворк». Вопрос в том, нужны ли приложению явные и компонуемые границы.

Матрица ответственности ​

ОбластьNestJSFastifyHono / Elysia / KoatRPCgo-like
Внешняя таблица маршрутовControllers и decoratorsFastify instanceЭкземпляр фреймворка или внешний роутерProcedure router, а не обычные REST-маршрутыВнешний фреймворк или приложение
Web handler ABIАбстракция request/reply, принадлежащая адаптеруNode request/replyСтандартный Fetch в центре Hono и Web Standard adaptersFetch/Node/Express/Fastify adaptersСтандартный (Request) => Response | Promise<Response>
Жизненный цикл приложенияApplication context и hooksready, listen, close, hooksЗависит от runtime adapter и фреймворкаОтветственность host/adapternewApp, App.run, App.stop, hooks, структурные Servers
Жизненный цикл ресурсовHooks контейнера/фреймворкаHooks плагинов и сервераОтветственность приложения/runtimeОтветственность приложения/adapterЯвные контракты Server.start(ctx) / stop(ctx) и владение адаптера
Композиция зависимостейNest container/providersPlugin decoration и encapsulationContext/env и композиция; общего DI-контейнера нетЯвный context factory и композиция routerЯвные конструкторы и functional options; DI-контейнера нет
Внутренний transportMicroservice transports и framework adaptersНе абстракция обнаружения сервисовНе абстракция обнаружения сервисовProcedure adapters и необязательный WebSocketTransport, Client, Listener, defineService, SSE ServerStream
Discovery и selectionЗависит от транспорта или внешнийВнешнийВнешниеВнешниеRegistry, Discovery, Watcher, Filters, пять политик Selector
RetryЗависит от фреймворка или провайдераЗависит от приложения/плагинаЗависит от приложенияЗависит от middleware/adapterПо умолчанию одна попытка; withRetry требует разрешения и общего числа попыток
StreamingЗависит от фреймворка/провайдераNode/Web stream choicesНативные Web Streams и API фреймворкаЗависит от HTTP/WS adapterWeb Streams; JSON or SSE server stream; Fetch unary/server-streaming; /native client-streaming/bidi
Глобальная инструментацияИнтеграция фреймворка/провайдераPlugin ecosystemMiddleware ecosystemMiddleware/adaptersЯвные wrappers; глобальные providers не устанавливаются

Подписи в первых пяти строках описывают архитектурную позицию, а не рейтинг качества. Владение таблицей маршрутов полезно, когда именно композиция маршрутов является задачей. Это просто другой выбор ответственности по сравнению с go-like, который оставляет маршруты приложению.

Жизненный цикл и Context ​

Текущий исходный код go-like определяет:

ts
interface Server {
  start(ctx: Context): Promise<void>
  stop(ctx: Context): Promise<void>
}

interface App {
  run(): Promise<void>
  stop(): Promise<void>
}

Контракт Server структурный. Нативный worker, listener, scheduler, подписка брокера, место назначения логов или провайдер телеметрии могут присоединиться к Core, если адаптер честно описывает момент допуска и конечное состояние.

Context go-like также структурен и внутри использует AbortSignal. Он предоставляет deadline(), done(), err() и value(key), а также конструкторы background, withCancel, withCancelCause, withTimeout, withDeadline, withoutCancel и withValue.

Это похоже на явный Context-first стиль Go, но не совместимо на уровне ABI с context.Context. Сам Context не предоставляет goroutine, channel или API gRPC. Правильный вопрос при миграции — «где через эту границу проходят отмена и владение?», а не «какое имя типа совпадает?».

Core не обещает остановку соседних Servers в обратном порядке. Он параллельно вызывает stop(ctx) у соседей, затем дожидается конечных Promise от start и объединяет ошибки. У Nest application context, графа плагинов Fastify, lifecycle Elysia или host adapter могут быть другими: порядок и семантика завершения могут отличаться. Сравнивайте фактического владельца, а не одно слово «graceful».

Transport и вызовы сервисов ​

Цепочка внутреннего вызова go-like намеренно разложена на части:

text
Client
  -> Discovery snapshot, optional
  -> ordered Filter callbacks, optional
  -> Selector.select
  -> opaque ServiceEndpoint URL
  -> Transport.dial or resident logical owner
  -> fetch(Request)
  -> @go-like/server route and unary handler
  -> read Response
  -> feedback and owner release

Типизированный Endpoint связывает проверку request и response через Struct с телом JSON Fetch. Это не IDL и не сгенерированный протокол. withEndpoint(...) выбирает прямой снимок при создании; прямые и полученные через Discovery снимки используют один и тот же Selector. Путь с in-process Memory Transport остаётся удобным первым тестом.

Транспортные опции NestJS для microservice, procedure adapters tRPC и транспорты Go-фреймворков не являются взаимозаменяемыми с этим DAG. У них могут отличаться identity маршрута, модель сериализации, пул соединений или слой retry. В сравнении нужно фиксировать эти различия, а не считать все варианты «RPC» одинаковыми.

Область retry и streaming ​

Самое важное отрицательное различие касается семантики:

  • Вызовы go-like по умолчанию делают ровно одну попытку.
  • withRetry(...) требует authorization: "idempotent" | "caller-approved", положительный maxAttempts и shouldRetry.
  • Authorization — это заявление вызывающей стороны, а не доказательство идемпотентности.
  • Retry может выбрать новый endpoint, поскольку каждая попытка заново проходит discovery и selection.
  • Ответ, который уже получен, но за которым последовала ошибка feedback или cleanup, не воспроизводится повторно.

Сравнительное исследование Go фиксирует другие значения по умолчанию и возможности: DefaultRetries в go-micro — не простое утверждение «пять запросов всего», поскольку граница цикла может дать шесть итераций, когда разрешение на retry остаётся истинным; публичная форма stream и реализация CloseSend по умолчанию также различаются у провайдеров. go-kratos сочетает генерацию Protobuf/gRPC с формами HTTP streaming, где у SSE и WebSocket различаются направления и поведение закрытия. Это выбор провайдера и архитектуры, а не недостающие флаги go-like.

Для go-like:

text
Web framework or Fetch Handler
  -> Web Streams, SSE, or WebSocket behavior owned by the application/framework

go-like internal Client/Transport
  -> one JSON body, or one SSE server stream when `stream: true`
  -> not a bidirectional multi-frame protocol

@go-like/transport-grpc-buf
  -> Fetch: Connect/gRPC-Web unary and server-streaming
  -> /native: standard gRPC unary, server-streaming, client-streaming, bidi

Web ReadableStream — не канал внутреннего RPC. Не сравнивайте потоковое тело HTTP с многофреймовым transport send/recv, будто это одна и та же возможность.

Сравнение runtime ​

Вопрос о runtimeДоказательство go-likeСледствие для сравнения
Может ли общий код использовать Fetch и AbortSignal?Root Web и выбранные Config/Transport providers используют стандартные Web API или внедрённый FetchПохожие цели переносимости возможны, но типы не эмулируют поведение runtime
Может ли Fetch везде передать custom PEM TLS, mTLS, ALPN и HTTP/2?Нативное поведение принадлежит Node transport subpath; root Fetch path не даёт всех этих настроекСравнивайте возможности host и import paths, а не только имена пакетов
Сохраняет ли приложение роутер фреймворка?Примеры Hono, Elysia и H3 передают нативные Fetch handlersgo-like дополняет владение маршрутизацией фреймворка
Доказывает ли версия пакета его публикацию?workspace:*, 0.0.1Нельзя делать вывод о доступности в npm или зрелости экосистемы

В текущем репозитории есть прямые исходные примеры для Hono, Elysia, H3 и vanilla Fetch. В нём нет актуального NestJS- или Fastify-моста и набора тестов совместимости. Это аудитория для миграции, а не поддерживаемая прямая интеграция.

Подробное сравнение по инструментам ​

NestJS ​

NestJS — конвенциональный фреймворк приложения. Его modules, providers, controllers, decorators, interceptors, pipes и application hooks образуют цельный контейнер и модель запросов. go-like не предоставляет совместимый с Nest контейнер модулей или мост для controllers.

Разумная граница интеграции — принадлежащий приложению адаптер, который реализует структурный Server go-like вокруг приложения Nest или его host. Такой адаптер должен определить, когда Nest допустил listener к работе, как stop(ctx) отображается на закрытие Nest и что происходит после timeout. Текущий репозиторий не доказывает наличие такого моста, поэтому документация не должна показывать прямой вызов вроде newNodeServer(nestApp, ...).

Fastify ​

Fastify владеет таблицей маршрутов, encapsulation плагинов, hooks и Node listener. Его граф плагинов полезен для сравнения областей видимости зависимостей, но decorate не является общим контейнером providers уровня Nest. go-like автоматически не преобразует ABI Fastify request/reply в Fetch Handler, и в репозитории нет протестированного актуального Fastify-моста.

Оставьте маршруты и плагины Fastify нативными. Если вы внедряете go-like, напишите явный структурный Server вокруг владельца Fastify или отдельно реализуйте Fetch-границу. Не называйте собственные request injection или native shutdown Fastify контрактом go-like Transport или Client.

Hono ​

Hono — наиболее ясно показанный пример дополнения. Текущий пример создаёт маршруты в Hono, передаёт app.fetch в newNodeServer и помещает этот host в Core App. Маршруты и middleware остаются во владении Hono; go-like владеет границей жизненного цикла host, если приложение выбирает такую композицию.

Elysia ​

Elysia предоставляет ориентированную на Bun модель композиции маршрутов и схем, а также Web Standard handler в соответствующем adapter path. Сохраните дерево маршрутов Elysia, decorators, derives, hooks, streams и поведение, специфичное для Bun. go-like может владеть App и явной границей ресурса, но не превращает .listen() в межruntime API go-like.

Koa ​

Koa — небольшое Node-ядро middleware без встроенного роутера. Это хороший пример фреймворка, который намеренно оставляет больше композиции приложения за пределами core. go-like не должен заполнять этот пробел добавлением роутера. Оставьте middleware Koa и внешний роутер нативными, а границу жизненного цикла или внутреннего вызова добавляйте только там, где она нужна.

tRPC ​

tRPC владеет типобезопасным procedure router и middleware процедур. Он может использовать Fetch, Node, Express, Fastify или WebSocket adapters, но не является Registry, Selector, connection pool или менеджером жизненного цикла приложения. Типизированный Endpoint go-like — это меньшая runtime-привязка Struct к телам JSON Fetch, а не конкурирующий procedure DSL или сгенерированный IDL.

go-micro и go-kratos ​

Эти проекты Go полезны как архитектурные ориентиры для Context-first вызовов, жизненного цикла сервисов, Registry, Discovery, Selector и транспортной терминологии. Они не являются целями совместимости:

  • Go context.Context и go-like Context разделяют намерение явной отмены, но их runtime-представления различаются.
  • Модель Registry watcher в go-micro и полные снимки-замены go-like не следует описывать как одинаковые потоки событий.
  • @go-like/protoc-gen-like генерирует Protobuf RPC с первым аргументом Context на основе Protobuf-ES. @go-like/transport-grpc-buf предоставляет unary и server-streaming Connect/gRPC-Web через Fetch; /native добавляет стандартный gRPC со всеми четырьмя видами вызовов, включая client-streaming и bidi. Этот путь независим от внутреннего пути Fetch/SSE.
  • Значения по умолчанию провайдеров go-micro и go-kratos, retry loops, half-close streams и default selectors зависят от версии. Используйте таблицу зафиксированных upstream commit в исследовательской записи и проверяйте её заново перед публикацией новой сравнительной версии.

Что выбрать ​

Если основная задача —...Начните с...Добавляйте go-like, когда...
Controllers, modules, decorators и DINestJSнужна явная граница вокруг существующего ресурса или внутреннего вызова и вы готовы написать адаптер
Node HTTP routes, hooks и plugin encapsulationFastifyнужна композиция lifecycle за пределами host или внутренние сервисные контракты
Web Standards routes между runtimeHonoнужны lifecycle App/Server, внутренние вызовы или владение провайдерами
Bun-first schema и route compositionElysiaнужны явные границы lifecycle и transport при сохранении Elysia
Минимальное Node middlewareKoa плюс роутернужен недостающий контракт жизненного цикла или внутреннего вызова, а не ещё один роутер
Типобезопасные процедурыtRPCтакже нужны явные service discovery, владение провайдерами или Core lifecycle
Go-стек микросервисовgo-micro или go-kratosвы строите отдельную TypeScript-композицию, а не source-совместимый порт
Межruntime TypeScript building blocks сервисовgo-likeиспользуйте только те пакеты и провайдеры, которые решают нужную границу

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

Опорные точки доказательств ​

Утверждения о go-like на этой странице можно проследить по текущему дереву и entrypoint пакетов:

  • README.md — область продукта и явные исключения;
  • packages/core/src/app.ts — App, Server, запуск, остановка и поведение timeout;
  • packages/web/src/context.ts — стандартный Handler и мост Context;
  • packages/client/src/index.ts — опции Client, pooling, retry и pipeline попытки;
  • packages/server/src/index.ts — внутренние унарные handlers и dispatch маршрутов;
  • packages/transport/src/types.ts и packages/transport/src/endpoint.ts — границы Fetch Request/Response и defineService;
  • packages/registry/src/types.ts и packages/registry/src/selector.ts — snapshots, filters, selectors и feedback.

В исследовательской записи также сохранены следующие зафиксированные внешние входные данные для сравнения:

URL выше — сравнительные источники, а не утверждение, что в рамках этой фазы документации каждая upstream-страница была загружена или повторно проверена. Перед изменением формулировки, зависящей от версии, заново проверьте release tags или commits.