架构设计内容分享(二百零三):SaaS系统的扩展开发实践

目录

标准化与个性化矛盾

个性化需求带来的挑战

扩展开发所需的能力

扩展开发的前端实现

前端插件的开发管理

前端插件的渲染实现


对于 SaaS 服务商来说,标准化产品和个性化需求是两个重要的方面。标准化产品指的是一种在各个客户之间共享的统一产品或服务。通过提供标准化产品,SaaS 服务商可以更有效地开发、部署和维护软件,降低成本并提升整体的可靠性和稳定性。

然而,不同的客户可能有不同的诉求,因此个性化需求也是需要考虑的因素。某些客户可能需要定制化的功能、设计或流程,以满足其独特的业务需求。为了满足这些个性化需求,SaaS 服务商需要进行额外的开发和支持,确保他们的产品能够适应不同客户的需求。

标准化与个性化矛盾

图片

标准化产品与个性化需求之间存在一定程度的矛盾:

  • 标准化产品可以提高效率,降低开发和维护成本,并使产品更易于扩展和升级。它们可以为广大客户提供一致的功能和体验,减少定制化工作量,加快产品交付速度。然而,标准化产品可能无法完全满足每个客户的特定需求。

  • 个性化需求强调满足客户的特殊要求和偏好。为了满足这些需求,服务商可能需要投入更多资源进行定制化开发和支持,增加复杂性和成本。此外,个性化需求还可能导致产品碎片化,增加维护的难度。

个性化需求带来的挑战

图片

从技术角度上来看,个性化需求带来一些挑战:

  1. 复杂性增加: 个性化需求可能导致系统的复杂性增加。定制化模块、功能和配置都会增加代码的复杂性,使得系统更难以理解、维护和扩展。以配置项为例,我们经常会为个性化需求增加 CSM 后台配置、系统配置、功能开关甚至一些硬编码条件,越来越多的配置项也意味着更多的条件分支,这无疑让代码变得更加的复杂。

  2. 维护困难: 大量个性化定制可能增加系统的维护难度。当系统需要更新和维护时,不同定制化模块的兼容性和稳定性可能成为问题,需要花费更多的人力去梳理现状。标准产品功能模块和个性化需求模块耦合到一起,会代码的膨胀速度更快;而且当租户不再续约,这些个性化需求的代码很可能变成系统中的死码,没有什么用又不能及时把这些代码清理掉。

  3. 技术债务: 过多的个性化定制可能会导致技术债务的积累。不合理的定制可能需要后续的重构和修复,增加了未来开发的困难度和成本。当系统需要更新和维护时,不同定制化模块的兼容性和稳定性可能成为问题。在标准产品的迭代升级的同时,还要兼顾已有的个性化模块。

  4. 资源消耗: 实现大量个性化需求可能需要投入更多的人力和资源。开发、测试、维护定制化模块会消耗额外的资源,可能影响项目的进度和成本。在有限的人力资源情况下,当个性化需求上投入较多的资源时,在标准产品功能投入的资源自然会减少,最终影响到标准产品的正常迭代。

那么,对于 SaaS 服务商来说,个性化需求是无法避免的,那么怎样去应对呢?通常,SaaS 服务商会为客户提供扩展开发的能力,在现有SaaS应用程序的基础上进行定制化修改和扩展,来满足特定个性化需求。这种方法可以帮助用户或企业在不完全从零开始的情况下,实现定制化的功能、界面和流程。这种扩展开发的好处在于:

  1. 更好地控制成本 技术交付团队以项目制的方式来交付和实施,资源的投入上更加灵活可控,而且可以收取一定的费用。

  2. 更利于开发维护 标准产品提供扩展开发的接入能力,将个性化需求模块与标准产品模块的代码隔离,降低了对标准产品代码的影响。

扩展开发所需的能力

图片

SaaS 系统提供扩展开发能力是为了让用户或开发者能够在现有的 SaaS 应用基础上进行定制化的开发和修改,以满足特定的业务需求。为了实现这一点,SaaS 系统可以采取以下方法来提供扩展开发能力:

  1. 开放的 API 和 SDK: SaaS 系统可以提供开放的应用程序接口(API)和软件开发工具包(SDK),使开发者能够访问和扩展 SaaS 应用的功能。API 可以用于与 SaaS 系统交互,而 SDK 可以用于创建定制化的模块和应用。以 API 接口为例,后端为二次开发提供了用户查询接口、部门查询接口、职位查询接口等,开发者可以直接使用这些接口进行相关业务的开发。

  2. 自定义插件和扩展: SaaS 系统可以支持开发者创建自定义的插件,以增强应用程序的功能。这些插件可以嵌入到 SaaS 应用中,以实现定制化的功能。允许开发者在插件中使用基础组件库和业务组件库,这有助于实现与品牌和用户体验的一致性。

  3. 业务逻辑定制: SaaS 系统可以允许开发者定制业务逻辑、工作流程和规则。这使得开发者能够根据业务需求调整应用的行为。为此后端提供了各个阶段的触发器,用于支持业务逻辑的定制。通过使用这些工具,开发者能够将 SaaS 应用与外部系统连接起来,实现数据交换和共享。

  4. 实时预览和调试: 提供实时预览和调试功能,使开发者能够快速查看定制化效果,并进行必要的调整和优化。而且我们提供了详细的文档帮助开发者充分了解如何使用提供的二次开发工具和能力。

通过提供这些能力,SaaS 系统可以为开发者和用户提供强大的扩展开发能力,使他们能够根据自己的需求定制化 SaaS 应用,从而更好地满足特定的业务和用户需求。

扩展开发的前端实现

图片

可以采用插件的方式来实现 SaaS 系统的扩展开发。这就需要为插件的开发和管理提供一系列工具和能力支持,确保插件能够顺利实现从开发到运维的整个生命周期。这些支持措施可以帮助插件开发者顺利地将插件集成到宿主系统中,并保障插件的有效运行和维护。

首先,需要让插件能够接入到宿主中并渲染出来,为此我们为各个端提供统一的基座 kit,通过基座将插件与系统集成在一起。基座提供了宿主环境配置、插件元数据处理、上下文通信等功能,并将数据同步给系统中各个 Slot 插槽,最终通过插槽将插件在正确的位置渲染出来。

其次,为插件的开发测试提供了丰富的工具支持,包括 CLI 工具、业务组件库、开发工具类库等。在这些工具的支持下,尽可能让开发者能够保持较高的开发效率。较好的工具支撑,除了能够快速实现需求交付之外,还能让开发者获得较好的开发体验。

另外,要确保插件能够稳定运行并及时维护,插件的安装和卸载以及版本控制等功能必不可少。目前,在插件管理后台和 CMS 后台中均支持插件的安装和卸载。插件开发者能够通过版本控制管理不同版本的插件,可以支持不同的租户安装不同版本的插件。

通过提供上述支持,可以帮助插件开发者更好地在宿主系统中集成、开发和管理插件,同时确保插件在整个生命周期中能够始终保持高质量、稳定性和可维护性。

前端插件的开发管理

图片

开发者使用 CLI 工具可以快速创建插件项目,并且可以通过宿主环境加载本地的插件进行开发调试。插件开发完成之后,代码推送到 Gitlab 仓库之后,会触发 CI/CD 打包构建插件。构建完成后会执行两个动作,首先将构建生成的静态资源上传到 CDN,其次是将插件数据通过插件服务存储到数据库中。

宿主环境会通过基座请求插件服务,获取到当前租户下已安装的插件,并且对这些插件数据进行加工和处理,为插件的渲染做准备。当用户访问到相应的插件时,基座会请求托管在 CDN 上的静态资源,将这些静态资源和宿主的上下文数据一起渲染成插件。用户使用渲染出来的插件即可完成相关的业务操作。

插件的安装卸载和版本管理均可在插件管理后台中完成。每次 CI/CD 构建成功之后,版本信息也会同步到数据库中。在插件首次构建成功之后,CMS 就可以为某个租户安装插件。开发者可以根据需要为租户切换不同的版本,通过控制版本可以完成线上测试或灰度发布等功能。

前端插件的渲染实现

插件渲染是插件体系中较为重要的环节之一,调研市面上已有的 SaaS 服务商,各家对插件的渲染方式是不一样的。大多数厂商会提供 iframe 內嵌的方式渲染插件,这种方案的好处是实现简单且与宿主环境有一定的隔离,安全性会高一些。但是,iframe 的缺点也较为明显,比如当 iframe 的窗口在宽高有限的情况下,很容易将其內部的 Modal 弹出遮挡住。因此,为了更好地交互和体验,一般还会提供在宿主环境中直接渲染的方案。为了和 iframe 作区分,我们可将这种方案称之为內联渲染方案。

在內联渲染上各家的差别较大,其中 Jira 是由服务端渲染实现,使用 FaaS 将插件的 UI 解析成结构化数据并渲染到系统中;它们比较极端的是,页面上的事件也要在 FaaS 处理之后再渲染,也就是说前端页面只将结构化解析成 UI,其他都是由 FaaS 完成。而另外一家 SaaS 服务商 Pipedrive 则是采用 JSON Scheme 的方式来描述插件,这种方式与 Low Code 方案比较相似,开发者生产的最终产物是一份 JSON,最终在前端页面将这份 JSON 解析渲染成 UI。

图片

我们可以选择用一种类似微前端的方案。这么做的好处是,不需要为渲染解析引擎付出额外的成本,无论是 FaaS 还是 JSON Scheme 方式都要做这个转换:代码 -> 结构化数据 -> UI,这两步转换所需要的成本并不低。而在我们的方案里,这个过程是:代码 -> bundle -> UI,与我们平时的项目开发并没有什么不同。

这个方案缺点也比较明显,插件渲染强依赖于 React 技术栈,特别是使用了 React 的一些特性,比如 React.lazy 等。但是,由于所有的应用端都是统一的 React 技术栈,因此这个缺点我们是可以接受的。与此同时,也可以借鉴和复用微前端的一些沙箱技术,将宿主环境和插件之间做好隔离。

在具体的渲染实现上,是通过 React.lazy 加载 bundle,但是我们改写了它的加载器,让它能够将 CDN 上的插件资源 bundle 渲染出来。有两种方法可以实现这种加载,一种是使用 script 标签加载,另外一种是使用 fetch 加载。但是无论哪种加载方式,都对 bundle 的打包构建有一定的要求,并不是随随便便的一个 bundle 我们都能加载成功,因此要在 CLI 中对 Webpack 构建打包 bundle 做一些相应的配置。

Provider 主要负责插件数据的请求和处理,会将租户下所有插件组织起来并按需渲染;槽位 Slot 将插件所需要的业务数据透传给插件,既包括用户、租户等全局信息也包括当前槽位所在的上下文数据(比如申请信息等)。从 React 组件开发的视角来看,Provider 主要负责数据的状态管理,Slot 是使用这些数据在对应的位置上将插件渲染出来。这里要考虑同一位置多个插件要按稳定顺序渲染以及插件的频繁重新渲染等细节问题,同时也要解决宿主环境的差异性等因素,为插件的渲染屏蔽掉宿主的差异。

  • 16
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

之乎者也·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值