设计规范与最佳实践
本文沉淀 BPMAX 插件开发中的推荐约定,帮助团队在多人协作和长期维护中降低风险。
学习目标
- 建立统一的插件设计规范
- 降低插件升级、回滚和协作成本
- 提高插件在生产环境中的可维护性
目录与命名规范
插件英文名规范
插件英文名应满足:
- 唯一
- 可读
- 与业务能力对应
不要频繁修改 en_name,否则会直接影响安装识别和升级判断。
文件与类命名规范
文件名、类名、配置 key 建议统一带插件前缀,降低冲突风险。
例如:
plugin_task_integration/
├── config.json
├── frontend/src/main.ts
├── server/src/controller/plugin_task_integration.js
├── server/src/service/plugin_task_integration.js
└── server/src/install/plugin_task_integration_install.js路径与路由命名规范
页面路径建议统一放在 /plugin/ 下,并与插件英文名或业务能力对应。
设计原则
尽量通过注册与 Hook 扩展,而不是侵入平台
能通过路由、插槽、流程组件、Hook 完成的能力,不要依赖修改平台页面或主流程代码。
前后端职责清晰
- 前端负责展示、交互和配置采集
- 后端负责鉴权、调用、校验和容错
配置与代码分离
业务规则、平台实例、第三方凭证等信息应尽量配置化,不要硬编码在页面或服务中。
建议把配置集中成明确结构:
const defaultConfig = {
enabled: false,
platform_id: '',
mapping_function: '',
retry_limit: 3,
};先保证可回滚,再追求复杂能力
复杂插件最重要的不是“功能全”,而是:
- 出问题能定位
- 升级后能兼容
- 失败后能补偿
工程实践
默认值设计
所有新增配置字段都应提供合理默认值,避免旧数据结构无法渲染或执行。
例如:
function normalizeConfig(config = {}) {
return {
enabled: Boolean(config.enabled),
platform_id: config.platform_id || '',
mapping_function: config.mapping_function || '',
retry_limit: config.retry_limit ?? 3,
};
}错误处理与日志
关键分支要有日志,外部调用要有上下文,错误信息要能区分:
- 参数错误
- 配置错误
- 网络错误
- 权限错误
日志建议至少保留可定位上下文:
think.logger.info('[plugin_task_integration] create task start', {
project_id: project.guid,
platform_id: config.platform_id,
});重试、幂等与超时
网络调用类插件必须同时考虑:
- 超时控制
- 可重试错误识别
- 幂等保护
安装脚本可重复执行
安装脚本不要假设“只会执行一次”。升级和重复安装场景下,仍应尽量安全执行。
例如:
async run() {
const exists = await this.model('plugin_config')
.where({ key: 'plugin_task_integration_initialized' })
.find();
if (exists?.id) {
return true;
}
await this.model('plugin_config').add({
key: 'plugin_task_integration_initialized',
value: '1',
});
return true;
}升级兼容性设计
每次新增字段或调整配置结构时,都要同步思考:
- 旧配置如何兼容
- 历史数据是否迁移
- 是否需要回滚方案
风险控制
避免覆盖平台同名文件
文件命名必须规避与平台或其他插件冲突的风险。
谨慎引入重依赖
外部依赖越重,插件升级、构建和调试成本越高。能复用平台能力时优先复用。
外部系统故障隔离
第三方系统失败时,不应让附加能力无条件拖垮主流程。
定时任务并发控制
只要存在重复触发可能,就要设计并发控制与幂等保护。
协作建议
文档同步
配置变更、安装要求、外部依赖变化都应同步更新文档。
示例优先
复杂能力优先提供最小可运行示例,便于后续维护者快速理解。
变更记录
建议为每次发布保留:
- 版本号
- 变更摘要
- 风险提示
