尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Unleash 代码库架构指南:特性开关平台的 CSR 分层、组合根模式与 AI 协作开发规范

Unleash 代码库架构指南:特性开关平台的 CSR 分层、组合根模式与 AI 协作开发规范 Unleash 代码库架构指南特性开关平台的 CSR 分层、组合根模式与 AI 协作开发规范【免费下载链接】unleashOpen-source feature management platform项目地址: https://gitcode.com/GitHub_Trending/un/unleash本文面向希望理解并参与 Unleash 开源特性开关Feature Flag平台开发的工程师与 AI 编码助手系统梳理当前仓库的整体架构、分层约定、关键设计模式与工程规范。读完本文你将掌握后端 Controller/Service/Store 分层与前端 React 数据流组织方式理解 Enterprise 如何通过preRouterHook钩子无 Fork 扩展 OSS 功能并能遵循组合根Composition Root、读模型/写模型分离、迁移与测试等约定快速定位代码、提交高质量的变更。项目概览前后端同仓的特性开关平台Unleash 是一个开源特性开关管理平台本仓库OSS 版本是一个 monorepo包含两大组成部分见 AGENTS.md后端基于 Node.js/TypeScript 的 REST API位于 src 目录前端基于 React/TypeScript 的单页应用SPA位于 frontend 目录。从 README.md 可以看出Unleash 的产品形态围绕“特性开关”展开开发者把新功能用开关包裹起来在生产环境以小批量、可控的方式逐步放量后端 SDK 通过unleash.isEnabled(AwesomeFeature)之类的调用在客户端本地评估开关状态而管理端Admin UI通过 Admin API 完成开关的创建、激活与策略配置。需要特别强调的是 Enterprise 与 OSS 的关系Enterprise 并不 Fork OSS而是通过独立的unleash-enterprise仓库基于钩子架构向 OSS 注入额外功能。因此当用户提到某个功能属于 Enterprise 特性时需要先确认 Enterprise 仓库的位置并同时在这两个仓库中开展工作。这是理解 Unleash 工程体系的第一条原则。上图展示了 Unleash 的系统级架构应用端通过 Backend SDK 与 Frontend SDK 本地评估特性开关Unleash 服务端通过 Client API供 SDK 拉取开关配置与 Admin API供管理界面配置对外提供服务。后文讨论的后端分层、路由与数据访问正是实现这套 API 的代码级骨架。后端架构CSRController-Service-Repository分层后端整体遵循CSRController、Service、Repository/Store模式。虽然新代码提倡按功能领域Feature而不是按层打包模块详见下文但经典的按层组织在传统组件中依然保留分层目录职责Controllersrc/lib/routes处理 HTTP 请求、校验输入、把业务逻辑委托给 Service、划定事务边界Servicesrc/lib/services业务逻辑层负责发出事件、管理事务Storesrc/lib/db数据访问层使用 Knex 查询构建器操作 PostgreSQL从入口的调用链可以验证这一分层确实被严格执行。以 src/lib/server-impl.ts 中的createApp第 279-402 行为例启动流程依次为创建数据库连接createDb→ 实例化全部 StorecreateStores→ 实例化全部 ServicecreateServices→ 组装 Express 应用getApp。Controller 永远通过 Service 访问数据绝不会直接触碰 Store。按功能领域打包的 Feature 模块与按层组织的传统组件不同Feature-based modules位于 src/lib/features每个领域内部自带自己的 controller、service、store 与类型定义例如feature-toggle、project、segment、change-request、release-plans等。以最核心的feature-toggle模块为例源码结构完整呈现了 CSR 的落地方式feature-toggle-controller.ts定义 HTTP 路由与 OpenAPI 请求/响应 Schema调用 Service 完成创建、更新、删除开关等操作feature-toggle-service.ts承载业务规则例如校验开关命名、处理变更事件、协调跨模块协作feature-toggle-store.ts封装开关的读写从源码可以看到getAll第 242 行、create第 469 行、update第 493 行等基础 CRUD 方法。关键设计模式AGENTS.md 明确列出了四条贯穿后端的关键模式它们也都能在源码中得到印证审计日志Audit-logService 层发出类型化事件如FeatureCreatedEvent既用于审计追踪也用于驱动读模型更新。事件在业务逻辑中被集中发出保证谁在什么时候改了什么可追溯。事务包装Transaction wrapper使用withTransactional()实现跨 Service 的原子操作常见约定是在 Controller 层发起事务。该工具函数在 src/lib/services/index.ts 中被大量使用例如withTransactional((db) createAccessService(db, config), db)见createServices第 198 行。Fake 实现每个 Store/Service 都配有 Fake 变体用于测试优先使用 Fake 而不是 Mock从而保证单元测试不依赖真实数据库。内部特性开关flagResolver.isEnabled()用于控制产品自身的运维级功能开关是 Unleash“用特性开关管理自身”的体现。技术栈Express PostgreSQLKnex TypeScriptES Modules。前端架构React SPA 的数据流与路由组织前端是一个通过 REST API 与后端通信的 React SPA代码集中在 frontend/src组件frontend/src/component 按功能领域组织的 React 组件Hooksfrontend/src/hooks 包含 71 个自定义 Hook负责数据获取与变更ContextsAccessContext权限、UIContextToast 提示、主题。前端同样有一组约定俗成的关键模式数据获取基于 SWR 的useApiGetter系列 Hook 处理 GET 请求并带缓存避免重复请求数据变更useApiHook 封装 POST/PUT/DELETE 并统一处理错误路由门控路由支持flag、enterprise、configFlag属性实现按内部开关、企业版能力或配置动态控制页面可见性样式基于 emotion 的 MUIstyled()组件一次性样式使用sx。技术栈React 18、Vite、Material-UIMUI、SWR 管理服务端状态。Enterprise 集成通过 Hook 扩展而非 ForkEnterprise 与 OSS 的集成方式是理解整个平台扩展性的关键其机制可以概括为四条详见 AGENTS.md入口unleash-enterprise/src/index.ts包装 OSS 的start()/create()钩子preRouterHook在 OSS 初始化完成之后、路由绑定之前执行扩展新增 50 Service、30 Store、50 Controller门控通过 License 中间件限制 Enterprise 特性。在 OSS 源码中可以直接看到钩子的调用位置。src/lib/app.ts 在完成鉴权、RBAC、维护模式等中间件装配后、注册IndexRouter之前执行了if (typeof config.preRouterHook function) { config.preRouterHook(app, config, services, stores, db); }见 src/lib/app.ts 第 203-205 行。而钩子的注入点位于 src/lib/create-config.ts第 870 行附近preRouterHook: options.preRouterHook它作为IUnleashConfig的一部分贯穿整个启动流程。在 src/lib/app.test.ts 中也能找到 should call preRouterHook 的测试用例验证该钩子在应用装配过程中的行为。Enterprise 专属特性包括Change Requests变更请求、SSOSAML/OIDC、Service Accounts、Signals Actions、Insights、SCIM、Private Projects、Release Plans、Safeguards 等。接口合并通过IEnterpriseServices extends IUnleashServices、IUnleashEnterpriseStores extends IUnleashStores实现类型层面的无缝扩展让 Enterprise 代码可以像使用 OSS 类型一样使用合并后的依赖。组合根模式Composition RootUnleash 遵循组合根模式所有依赖在应用启动时一次性装配完成而不是散落在代码库各处。每个 Service 都配有专门的组合根函数来负责自身及依赖的创建。OSS 组合根src/lib/db/index.ts →createStores()第 75 行使用 Knex 连接实例化全部 Storesrc/lib/services/index.ts →createServices()第 198 行使用 Store 配置实例化全部 Servicesrc/lib/server-impl.ts → 编排整体顺序DB → Stores → Services → App。Enterprise 组合根enterprise/src/util/setup-stores.ts创建 Enterprise Store 并与 OSS Store 合并enterprise/src/util/setup-services.ts使用合并后的 Store 创建 Enterprise Serviceenterprise/src/create-enterprise-routes.ts在preRouterHook中把所有东西接线完成。这条规则为什么重要永远不要在代码行内new一个 Service 或 Store而应通过构造函数注入接收依赖。这样做一方面让依赖图显式化、可测试可以用 Fake 注入另一方面避免隐式耦合。从createServices的实现可以看到大量依赖如AccessService、ApiTokenService、LastSeenService都是先构造局部变量再以构造参数形式传递这正是组合根模式的直接体现。读模型 vs 写模型读写分离的实践为了避免 Store 被复杂查询压垮Unleash 将读写关注点分离写模型Stores负责单个实体的 CRUD 操作保持查询简单insert、update、delete、getById位于 src/lib/db 或各 feature 目录典型例子FeatureToggleStore只负责开关的基础增删改查。读模型Read Models负责复杂查询、聚合、跨领域查询与反规范化视图针对特定读取场景优化看板、列表、报表位于各 feature 目录下的read-models/子目录典型例子FeatureStrategiesReadModel、ProjectOwnersReadModel、FeatureSearchReadModel。在 src/lib/features/feature-toggle 中可以看到 features-read-model.ts 与 feature-strategies-read-model.ts 等实现。何时应该使用读模型查询跨多张表、需要复杂 JOIN需要反规范化数据以提升性能正在构建看板/概览类端点查询无法对应到单个实体的生命周期不想暴露整个写模型只需要其他模块的某个值。约定模式Service 在 Store写与读模型读之间协调Controller 只能调用 Service 或读模型绝不能直接调用 Store。这条边界保证了分层清晰也让读模型可以独立优化而不影响写路径。开发哲学与编码规范AGENTS.md 强调三条核心原则始终测试代码优先自动化测试而非手工测试编写可维护的代码代码即沟通清晰与可读性至关重要提交前三思。详细的编码标准以架构决策记录ADR的形式沉淀在 contributing/ADRs 目录下分为三组后端contributing/ADRs/back-end如 REST API 规范、SQL 标准、正确类型依赖等前端contributing/ADRs/front-end如组件命名、数据获取方式、表单架构、样式方案等全局contributing/ADRs/overarching如领域语言、日志规范、请求/响应 Schema 分离等。此外还有一条直接可执行的编码约定优先使用Boolean(someVariable)而不是!!someVariable。数据库迁移规范迁移文件统一存放在 src/migrations从仓库内容可以看到从 2014 年初始 Schema 到近期功能如 Safeguards、API Tokens v2、Edge 可观测性的数百个迁移文件绝不修改已经合并的迁移需要变更时创建新的迁移每个迁移必须包含up和down两个方法使用pnpm db-migrate create name创建新迁移。测试策略Unleash 采用分层测试策略工具与范围如下层级工具说明后端Vitest SupertestAPI 测试使用 Fake Store 实现隔离前端Vitest Testing Library组件与 Hook 测试E2ECypressfrontend/cypress端到端流程验证运行测试的命令pnpm test # 全部测试 pnpm test:frontend # 仅前端 pnpm test:backend # 仅后端Fake 实现是后端测试的基石每个 Store/Service 都有对应 Fake例如src/test/fixtures/下的各类 fake store测试优先注入 Fake 而非使用 Mock 库保证测试环境与真实行为高度一致。关键文件速查表OSS 入口与装配文件用途src/server.ts主入口src/lib/app.tsExpress 应用装配、中间件栈src/lib/routes/index.ts路由注册src/lib/services/index.tsService 工厂createServicessrc/lib/db/index.tsStore 工厂createStores模式参考Pattern References模式示例位置Controllersrc/lib/features/feature-toggle/feature-toggle-controller.tsServicesrc/lib/features/feature-toggle/feature-toggle-service.tsStore写模型src/lib/features/feature-toggle/feature-toggle-store.ts读模型src/lib/features/feature-toggle/features-read-model.ts 等组合根src/lib/services/index.tsAPI HookGETfrontend/src/hooks/api/getters/useFeature/useFeature.tsAPI Hook变更frontend/src/hooks/api/actions/useFeatureApi.tsFake Storesrc/test/fixtures/fake-feature-toggle-store.ts结语给 AI 编码助手的行动清单对于希望在本仓库中高效工作的 AI 编码助手或开发者可以把 AGENTS.md 的规范浓缩为以下操作清单先定位领域再写代码新功能优先放进 src/lib/features 下对应领域的 controller/service/store而不是散落到按层组织的旧目录遵守分层边界Controller 调 ServiceService 协调 Store写与读模型读永不直接使用 Store依赖走构造注入不new服务通过组合根函数装配测试时注入 FakeEnterprise 功能跨仓库协作涉及 Enterprise 特性时必须同时打开unleash-enterprise仓库通过preRouterHook扩展而非修改 OSS数据库变更新建迁移不改旧迁移用pnpm db-migrate create生成新迁移并实现up/down提交前跑测试用pnpm test验证全量测试遵循 ADR 中记录的编码规范。【免费下载链接】unleashOpen-source feature management platform项目地址: https://gitcode.com/GitHub_Trending/un/unleash创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表