搜 索

Backstage从入门到放弃

  • 5阅读
  • 2026年02月14日
  • 0评论
首页 / 编程 / 正文

〇、写在前面

如果你的公司有超过 3 个微服务,并且每次找个 API 文档都要翻遍 Confluence、SharePoint、钉钉群聊和某位离职同事的脑子,那么恭喜你——你可能需要 Backstage。

如果你的公司只有一个单体应用,那你可以现在就放弃了,省下来的时间去健身房撸个铁不香吗?

Backstage 是 Spotify 在 2020 年开源的内部开发者门户(Internal Developer Portal, IDP),后来捐给了 CNCF,目前是 Incubating 项目。它的核心愿景是:把所有开发者需要的东西,塞进一个统一的界面里

听起来很美好对吧?就像"我要把所有支付系统统一到一个平台"一样美好。


一、Backstage 是什么?

1.1 一句话定义

Backstage 是一个构建开发者门户的开源框架(注意,是框架,不是开箱即用的产品)。

1.2 核心功能三板斧

graph TB subgraph Backstage["🏠 Backstage 核心能力"] SC["📦 Software Catalog
软件目录"] ST["🚀 Software Templates
软件模板"] TD["📖 TechDocs
技术文档"] end SC --> |"统一管理"| Services["微服务 / API / 库 / 网站"] ST --> |"一键创建"| Scaffold["标准化项目脚手架"] TD --> |"Docs as Code"| Docs["Markdown → 在线文档站"] subgraph Plugins["🔌 插件生态"] P1["Kubernetes"] P2["CI/CD"] P3["Cloud Costs"] P4["PagerDuty"] P5["还有100+..."] end Backstage --> Plugins style Backstage fill:#1a1a2e,stroke:#16213e,color:#e0e0e0 style Plugins fill:#0f3460,stroke:#16213e,color:#e0e0e0 style SC fill:#533483,stroke:#16213e,color:#e0e0e0 style ST fill:#533483,stroke:#16213e,color:#e0e0e0 style TD fill:#533483,stroke:#16213e,color:#e0e0e0
核心功能干什么用对标产品
Software Catalog统一注册和查看所有软件资产(服务、API、组件、资源)内部版 ServiceNow CMDB
Software Templates标准化创建新项目,自动化 scaffolding内部版 Yeoman / CookieCutter
TechDocsDocs-as-Code,把 Markdown 渲染成文档站内部版 GitBook / Read the Docs

1.3 架构全景图

graph TB subgraph Frontend["🖥️ Frontend (React SPA)"] UI["统一 UI Shell"] FP1["Catalog Plugin UI"] FP2["TechDocs Plugin UI"] FP3["Template Plugin UI"] FP4["Custom Plugin UI"] end subgraph Backend["⚙️ Backend (Node.js)"] API["Backend API Gateway"] BP1["Catalog Backend"] BP2["TechDocs Backend"] BP3["Auth Backend"] BP4["Scaffolder Backend"] BP5["Search Backend"] end subgraph Infra["🗄️ 基础设施"] DB[("PostgreSQL")] SCM["Git Provider
(GitHub/GitLab/Bitbucket)"] CICD["CI/CD
(Jenkins/GitHub Actions)"] K8S["Kubernetes"] CLOUD["Cloud Provider
(AWS/Azure/GCP)"] end UI --> API API --> BP1 & BP2 & BP3 & BP4 & BP5 BP1 --> DB BP1 --> SCM BP2 --> SCM BP4 --> SCM & CICD BP5 --> DB style Frontend fill:#2d3436,stroke:#636e72,color:#dfe6e9 style Backend fill:#2d3436,stroke:#636e72,color:#dfe6e9 style Infra fill:#2d3436,stroke:#636e72,color:#dfe6e9
划重点:Backstage 本质上是一个 React + Node.js 的全栈应用,前端是 SPA,后端是一堆插件化的 API 服务。数据存在 PostgreSQL 里,和你的 Git、CI/CD、Cloud 通过插件集成。

二、Software Catalog:你的服务大管家

2.1 核心概念

Catalog 是 Backstage 的灵魂。它用 YAML 文件(catalog-info.yaml)来描述你的软件资产,这些 YAML 文件通常放在各个 Repo 的根目录。

# catalog-info.yaml - 放在你的服务仓库根目录
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: deposit-service
  description: AstraTech 存款服务 - 管理所有存款相关业务
  annotations:
    github.com/project-slug: astratech/deposit-service
    backstage.io/techdocs-ref: dir:.
  tags:
    - java
    - spring-boot
    - payments
  links:
    - url: https://grafana.astratech.ae/d/deposit
      title: Grafana Dashboard
      icon: dashboard
spec:
  type: service
  lifecycle: production
  owner: team-deposit
  system: payment-platform
  providesApis:
    - deposit-api
  consumesApis:
    - npss-api
    - vis-api
  dependsOn:
    - resource:deposit-db
    - component:escrow-service

2.2 实体关系模型

erDiagram Domain ||--|{ System : contains System ||--|{ Component : contains System ||--|{ API : exposes Component ||--|{ API : "provides/consumes" Component }|--|| Group : "owned by" Group ||--|{ User : "has members" Component ||--o{ Resource : "depends on" Domain { string name "e.g. payments" string description } System { string name "e.g. payment-platform" string owner } Component { string name "e.g. deposit-service" string type "service/library/website" string lifecycle "production/experimental" } API { string name "e.g. deposit-api" string type "openapi/asyncapi/grpc" string definition "spec内容" } Group { string name "e.g. team-deposit" string type "team/department" } User { string name "e.g. joey" string email } Resource { string name "e.g. deposit-db" string type "database/s3-bucket" }

2.3 以 AstraTech 为例

假设要把 Deposit Team 的系统全部注册到 Catalog,大概长这样:

graph LR subgraph Domain_Payments["🏦 Domain: Payments"] subgraph System_PaymentPlatform["💳 System: Payment Platform"] NPSS["NPSS Service
Aani Instant Payments"] VIS["VIS/VISII Service
Virtual Account Mgmt"] DEP["Deposit Service
Core Deposits"] TTS["TTS Service
Visa Installments"] ESC["Escrow Service"] CARDS["Cards Service"] EX["Exchange Service"] RTP["RTP Service"] end end subgraph Resources["🗄️ Resources"] DB1[("Deposit DB")] DB2[("NPSS DB")] MQ["Kafka / RabbitMQ"] end subgraph APIs["📡 APIs"] A1["Deposit API
OpenAPI 3.0"] A2["NPSS API
ISO 20022"] A3["VIS API"] end DEP --> DB1 NPSS --> DB2 DEP --> MQ DEP --> A1 NPSS --> A2 VIS --> A3 NPSS -.-> DEP TTS -.-> DEP style Domain_Payments fill:#1B1464,stroke:#0c2461,color:#dfe6e9 style System_PaymentPlatform fill:#0a3d62,stroke:#0c2461,color:#dfe6e9
现实检查:要让所有团队都老老实实写 catalog-info.yaml,难度约等于让所有开发者都写单元测试。所以 Backstage 也支持从 LDAP/AD、GitHub Org、Kubernetes 等地方自动发现和导入实体。

三、Software Templates:一键生成标准项目

3.1 它解决什么问题?

每次新建一个微服务,你是不是要:

  1. 创建 Git 仓库
  2. 复制粘贴某个"模板项目"
  3. 改一堆 pom.xml / build.gradle 里的名字
  4. 配 CI/CD Pipeline
  5. 注册到服务发现
  6. 创建 Jira Board
  7. 然后发现忘了改某个配置,线上出 Bug

Software Templates 就是把上面这些步骤全部自动化。

3.2 模板工作流

sequenceDiagram actor Dev as 开发者 participant BS as Backstage UI participant SC as Scaffolder Backend participant GIT as GitHub/GitLab participant CI as CI/CD Pipeline participant K8S as Kubernetes Dev->>BS: 1. 选择模板
"New Spring Boot Service" BS->>Dev: 2. 填写表单
(服务名、团队、描述...) Dev->>BS: 3. 提交 BS->>SC: 4. 触发 Scaffolder SC->>SC: 5. 渲染模板
(Nunjucks/Cookiecutter) SC->>GIT: 6. 创建仓库 + 推送代码 SC->>GIT: 7. 注册 catalog-info.yaml SC->>CI: 8. 触发首次 CI 构建 SC->>K8S: 9. (可选) 创建 namespace SC->>BS: 10. 完成 ✅ BS->>Dev: 11. 跳转到新服务页面

3.3 模板定义示例

# template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: springboot-service
  title: Spring Boot 微服务模板
  description: 创建一个标准的 Spring Boot 微服务,包含 CI/CD 和监控
  tags:
    - java
    - spring-boot
    - recommended
spec:
  owner: team-platform
  type: service

  # === 第一步:收集参数 ===
  parameters:
    - title: 基本信息
      required:
        - name
        - owner
        - description
      properties:
        name:
          title: 服务名称
          type: string
          description: 例如 deposit-service
          pattern: '^[a-z][a-z0-9-]*$'
        owner:
          title: 所属团队
          type: string
          ui:field: OwnerPicker
        description:
          title: 服务描述
          type: string

    - title: 技术选型
      properties:
        javaVersion:
          title: Java 版本
          type: string
          enum: ['17', '21']
          default: '21'
        database:
          title: 数据库
          type: string
          enum: ['postgresql', 'mysql', 'none']
          default: 'postgresql'

  # === 第二步:执行动作 ===
  steps:
    - id: fetch-template
      name: 拉取模板
      action: fetch:template
      input:
        url: ./skeleton  # 模板文件目录
        values:
          name: ${{ parameters.name }}
          owner: ${{ parameters.owner }}
          javaVersion: ${{ parameters.javaVersion }}

    - id: publish
      name: 创建 Git 仓库
      action: publish:github
      input:
        allowedHosts: ['github.com']
        repoUrl: github.com?owner=astratech&repo=${{ parameters.name }}
        description: ${{ parameters.description }}

    - id: register
      name: 注册到 Catalog
      action: catalog:register
      input:
        repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
        catalogInfoPath: /catalog-info.yaml

  output:
    links:
      - title: 打开仓库
        url: ${{ steps.publish.output.remoteUrl }}
      - title: 查看服务
        entityRef: ${{ steps.register.output.entityRef }}

四、TechDocs:让文档不再躺在 Confluence 里吃灰

4.1 核心理念:Docs as Code

graph LR A["📝 Markdown 文件
(存在代码仓库里)"] --> B["🔧 MkDocs 构建"] B --> C["📦 静态 HTML"] C --> D["☁️ 存储
(S3/GCS/本地)"] D --> E["🖥️ Backstage 渲染"] style A fill:#6c5ce7,stroke:#5f27cd,color:#fff style B fill:#00b894,stroke:#00cec9,color:#fff style C fill:#fdcb6e,stroke:#ffeaa7,color:#2d3436 style D fill:#e17055,stroke:#d63031,color:#fff style E fill:#0984e3,stroke:#74b9ff,color:#fff

4.2 文档结构

your-service-repo/
├── catalog-info.yaml          # 注册到 Backstage
├── mkdocs.yml                 # MkDocs 配置
├── docs/
│   ├── index.md               # 首页
│   ├── getting-started.md     # 快速开始
│   ├── architecture.md        # 架构说明
│   ├── api-reference.md       # API 参考
│   └── runbook.md             # 运维手册
└── src/
    └── ...                    # 你的代码
# mkdocs.yml
site_name: Deposit Service
nav:
  - Home: index.md
  - Getting Started: getting-started.md
  - Architecture: architecture.md
  - API Reference: api-reference.md
  - Runbook: runbook.md
plugins:
  - techdocs-core
真话时间:TechDocs 体验说实话一般般。MkDocs 的渲染能力有限,不支持复杂布局。如果你们已经在用 Confluence 并且用得还行,TechDocs 可能不是迁移的充分理由。

五、插件生态:Backstage 的真正杀手锏

Backstage 本身只是个框架,真正的价值在于插件生态。

5.1 官方 & 热门插件

mindmap root((Backstage
插件生态)) CI/CD GitHub Actions Jenkins GitLab CI ArgoCD Tekton 监控 & 可观测 Grafana Prometheus Datadog PagerDuty Opsgenie 云 & 基础设施 Kubernetes AWS GCP Azure Terraform 安全 Snyk SonarQube Vault 协作 Jira Confluence Slack API 管理 OpenAPI / Swagger AsyncAPI GraphQL 成本 Cloud Cost Kubecost

5.2 插件架构

graph TB subgraph Plugin["🔌 一个 Backstage 插件的结构"] FE["Frontend Plugin
@backstage/plugin-xxx
React 组件"] BE["Backend Plugin
@backstage/plugin-xxx-backend
Express Router"] Common["Common
@backstage/plugin-xxx-common
共享类型/工具"] end FE --> |"HTTP API"| BE FE --> Common BE --> Common subgraph Integration["外部集成"] ExtAPI["外部 API
(GitHub/Jira/K8s...)"] ExtDB["插件自有表
(PostgreSQL)"] end BE --> ExtAPI BE --> ExtDB style Plugin fill:#2d3436,stroke:#636e72,color:#dfe6e9 style Integration fill:#2d3436,stroke:#636e72,color:#dfe6e9

5.3 写一个自定义插件(伪代码)

// packages/app/src/plugins.ts
// 前端:注册一个显示 NPSS 交易状态的插件

import { createPlugin, createRoutableExtension } from '@backstage/core-plugin-api';

export const npssPlugin = createPlugin({
  id: 'npss-dashboard',
  routes: {
    root: rootRouteRef,
  },
});

export const NpssDashboardPage = npssPlugin.provide(
  createRoutableExtension({
    name: 'NpssDashboardPage',
    component: () =>
      import('./components/NpssDashboard').then(m => m.NpssDashboard),
    mountPoint: rootRouteRef,
  }),
);

六、部署方案

6.1 部署拓扑

graph TB subgraph Production["🚀 生产环境部署"] LB["Load Balancer
(Nginx / ALB)"] subgraph AppLayer["Application"] FE["Frontend
(Static Files / CDN)"] BE1["Backend Instance 1"] BE2["Backend Instance 2"] end DB[("PostgreSQL
(RDS / CloudSQL)")] CACHE["Redis
(可选, 用于Search)"] OBJ["Object Storage
(S3/GCS, TechDocs用)"] end LB --> FE LB --> BE1 & BE2 BE1 & BE2 --> DB BE1 & BE2 --> CACHE BE1 & BE2 --> OBJ style Production fill:#1a1a2e,stroke:#16213e,color:#e0e0e0 style AppLayer fill:#0f3460,stroke:#16213e,color:#e0e0e0

6.2 部署选项对比

方式复杂度适合场景备注
Docker ComposePoC / 小团队最快上手
Kubernetes (Helm)⭐⭐⭐中大型企业官方有 Helm Chart
Kubernetes (自定义)⭐⭐⭐⭐深度定制自己写 Deployment YAML
Roadie (SaaS)不想运维托管版 Backstage,要钱💰
Port / Cortex不想运维竞品 SaaS,各有千秋

七、快速上手:10 分钟跑起来

7.1 环境要求

  • Node.js 18+ (推荐 20 LTS)
  • Yarn 1.x(是的,还是 Classic Yarn 🤦)
  • Docker(用于 PostgreSQL)
  • Git

7.2 创建项目

# 1. 用官方 CLI 创建
npx @backstage/create-app@latest

# 2. 按提示输入项目名
? Enter a name for the app [required] astratech-portal

# 3. 进入项目
cd astratech-portal

# 4. 启动开发环境
yarn dev

7.3 项目结构

astratech-portal/
├── app-config.yaml           # 主配置文件 ⚡
├── app-config.production.yaml # 生产配置
├── catalog-info.yaml          # Backstage 自身的 catalog 注册
├── packages/
│   ├── app/                   # 前端 React 应用
│   │   ├── src/
│   │   │   ├── App.tsx        # 路由和插件注册
│   │   │   └── components/    # 自定义组件
│   │   └── package.json
│   └── backend/               # 后端 Node.js 应用
│       ├── src/
│       │   └── index.ts       # 后端入口
│       └── package.json
├── plugins/                   # 自定义插件放这里
└── package.json

7.4 核心配置

# app-config.yaml
app:
  title: AstraTech Developer Portal
  baseUrl: http://localhost:3000

backend:
  baseUrl: http://localhost:7007
  database:
    client: pg
    connection:
      host: localhost
      port: 5432
      user: backstage
      password: backstage

auth:
  providers:
    microsoft:  # Azure AD 集成
      development:
        clientId: ${AZURE_CLIENT_ID}
        clientSecret: ${AZURE_CLIENT_SECRET}
        tenantId: ${AZURE_TENANT_ID}

catalog:
  locations:
    # 本地示例
    - type: file
      target: ../../examples/entities.yaml
    # 从 GitHub Org 自动发现
    - type: github-org
      target: https://github.com/astratech
    # 从 GitHub 仓库读取
    - type: url
      target: https://github.com/astratech/deposit-service/blob/main/catalog-info.yaml

八、适用性评估:什么时候该用,什么时候该放弃

8.1 决策流程图

flowchart TD START(["🤔 我们需要 Backstage 吗?"]) --> Q1{"公司有多少
微服务/组件?"} Q1 -->|"< 10"| NO1["❌ 可能不需要
一个 Confluence 页面就够了"] Q1 -->|"10 ~ 50"| Q2{"有没有专人
维护内部工具?"} Q1 -->|"> 50"| Q3{"能接受 3-6 个月
的建设周期吗?"} Q2 -->|"没有"| NO2["❌ 考虑 SaaS 方案
(Roadie/Port/Cortex)"] Q2 -->|"有"| Q3 Q3 -->|"不能"| NO3["❌ 考虑 SaaS 方案
或者先用 Wiki + 手动管理"] Q3 -->|"能"| Q4{"开发团队
熟悉 React + TypeScript?"} Q4 -->|"不熟"| MAYBE["⚠️ 需要额外学习成本
但仍然可行"] Q4 -->|"熟"| Q5{"管理层支持
投入资源?"} MAYBE --> Q5 Q5 -->|"不支持"| NO4["❌ 没有自上而下的推动
内部平台注定失败"] Q5 -->|"支持"| YES(["✅ 上 Backstage!"]) style START fill:#6c5ce7,stroke:#5f27cd,color:#fff style YES fill:#00b894,stroke:#00cec9,color:#fff style NO1 fill:#d63031,stroke:#e17055,color:#fff style NO2 fill:#d63031,stroke:#e17055,color:#fff style NO3 fill:#d63031,stroke:#e17055,color:#fff style NO4 fill:#d63031,stroke:#e17055,color:#fff style MAYBE fill:#fdcb6e,stroke:#f9ca24,color:#2d3436

8.2 适用场景 ✅

场景为什么适合
微服务数量 50+人脑已经记不住谁依赖谁了
多团队协作需要统一的服务发现和所有权管理
频繁创建新服务Software Templates 能节省大量时间
文档散落各处TechDocs 把文档和代码绑定
需要统一的开发者体验一站式门户比 N 个工具跳来跳去强
已有 Kubernetes 基础设施K8s 插件是 Backstage 最成熟的插件之一

8.3 不适用场景 ❌

场景为什么不适合
团队 < 20 人投入产出比不合算
单体架构Catalog 没啥可管的
没有 DevOps 文化Backstage 需要团队主动维护 catalog-info.yaml
追求开箱即用Backstage 需要大量定制开发
技术栈不含 TypeScript/React二次开发和插件维护会很痛苦

8.4 ROI 估算模型

quadrantChart title Backstage ROI 评估矩阵 x-axis "实施复杂度低" --> "实施复杂度高" y-axis "业务价值低" --> "业务价值高" quadrant-1 "优先实施" quadrant-2 "战略投资" quadrant-3 "快速见效" quadrant-4 "谨慎评估" "Software Catalog": [0.45, 0.85] "Software Templates": [0.35, 0.70] "TechDocs": [0.25, 0.40] "K8s Plugin": [0.55, 0.75] "CI/CD Integration": [0.60, 0.65] "Custom Plugins": [0.80, 0.60] "Auth (Azure AD)": [0.50, 0.50] "Cost Management": [0.70, 0.45]

九、Backstage vs 竞品

graph LR subgraph OpenSource["🆓 开源"] BS["Backstage
⭐ 29k+ GitHub Stars"] end subgraph SaaS["💰 SaaS"] RD["Roadie
托管版 Backstage"] PT["Port"] CX["Cortex"] OI["OpsLevel"] end subgraph DIY["🔨 自建"] WIKI["Confluence/Wiki
+ 自定义脚本"] end style OpenSource fill:#00b894,stroke:#00cec9,color:#fff style SaaS fill:#6c5ce7,stroke:#5f27cd,color:#fff style DIY fill:#fdcb6e,stroke:#f9ca24,color:#2d3436
维度BackstageRoadiePortCortex
价格免费(但要人力)$$$$$$$$$
定制性🟢 极高🟡 中等🟡 中等🟡 中等
上手速度🔴 慢(3-6月)🟢 快(1-2周)🟢 快🟢 快
维护成本🔴 高🟢 低🟢 低🟢 低
插件生态🟢 最丰富🟢 兼容 Backstage🟡 自有生态🟡 自有生态
数据控制🟢 完全自主🟡 SaaS🟡 SaaS🟡 SaaS
社区支持🟢 CNCF + 活跃社区🟡 商业支持🟡 商业支持🟡 商业支持

十、实施路线图建议

gantt title AstraTech Backstage 实施路线图 dateFormat YYYY-MM-DD axisFormat %Y-%m section Phase 0 - PoC 环境搭建 & 评估 :p0a, 2025-03-01, 2w 核心团队培训 :p0b, after p0a, 1w PoC Demo & 决策 :milestone, p0c, after p0b, 0d section Phase 1 - MVP Azure AD 认证集成 :p1a, after p0c, 2w Software Catalog 建设 :p1b, after p0c, 4w Deposit Team 服务注册 :p1c, after p1b, 2w TechDocs 基础搭建 :p1d, after p1b, 2w section Phase 2 - 扩展 Software Templates 开发 :p2a, after p1c, 4w CI/CD 插件集成 :p2b, after p1c, 3w K8s 插件集成 :p2c, after p2b, 3w 其他团队 onboard :p2d, after p2a, 6w section Phase 3 - 成熟 自定义插件开发 :p3a, after p2d, 8w 全公司推广 :p3b, after p2d, 4w 持续运维 & 优化 :p3c, after p3b, 12w

十一、踩坑指南(从放弃到入门?)

🕳️ 坑 1:版本升级是噩梦

Backstage 的发布节奏非常快(几乎每周都有新版本),而且不保证向后兼容。每次升级都可能需要修改大量代码。

# 官方升级工具,但不要太相信它
npx @backstage/cli versions:bump
建议:不要追最新版本。选一个稳定版本,每季度评估一次是否升级。

🕳️ 坑 2:Yarn 1.x 的诅咒

是的,2025 年了,Backstage 官方仍然推荐 Yarn Classic。虽然有社区方案支持 Yarn Berry 和 pnpm,但官方文档和工具链都是基于 Yarn 1.x 的。

🕳️ 坑 3:插件质量参差不齐

官方 marketplace 列出了 200+ 插件,但很多是社区贡献的,质量和维护状态各不相同。使用前一定要检查:最后更新时间、GitHub stars、是否有活跃维护者。

🕳️ 坑 4:认证和权限系统复杂

Backstage 的权限系统(Permission Framework)是后来加的,配置复杂且文档不完善。如果你需要细粒度的 RBAC,准备花不少时间。

🕳️ 坑 5:搜索功能是半成品

内置的搜索引擎(Lunr)只适合小规模使用。大规模部署需要集成 Elasticsearch 或 OpenSearch,额外增加运维负担。


十二、总结:到底该入门还是放弃?

pie title 我的最终推荐 "值得尝试 (PoC先行)" : 45 "考虑SaaS替代品" : 25 "暂时不需要" : 15 "直接放弃" : 15

给 AstraTech 的建议

推荐策略:PoC 先行,小步快跑

  1. 先做一个 2 周的 PoC:用 Docker Compose 部署一个最小化的 Backstage,把 Deposit Team 的几个核心服务注册进去,让团队感受一下 Software Catalog 的价值。
  2. 聚焦 Catalog,暂缓其他:Software Catalog 是最核心也是最容易产生价值的功能。Templates 和 TechDocs 可以后续再加。
  3. 评估 Roadie 作为 Plan B:如果 PoC 效果好但没有足够的人力做自建运维,Roadie(托管版 Backstage)是一个合理的备选。
  4. 自上而下推动:内部开发者门户必须有管理层支持和强制要求,否则注定成为又一个没人维护的内部项目。

一句话总结

Backstage 就像是开发者世界的"超级 App"——理念超前、生态丰富、但组装难度约等于从零开始拼一台高达。适合有能力有耐心的团队,不适合想要银弹的管理者。

参考资料

评论区
暂无评论
avatar