这是一篇我想写了很久的文章。一直以来,企业软件前端工程体系处于一个很尴尬的局面,无数前端对它有过各种吐槽:技术栈老旧、封闭,体验差,而项目和交付经理又会觉得开发效率太低。据我所见,大部分吐槽的人并没有理解造成这些状况的深层原因,或者说,当自己去构建这么一套体系的时候,并不理解在选型和技术集成过程中,存有哪些可能的决策点。

本文尝试从一些角度去给出自己的见解,为了说明构建这个领域前端技术体系的种种考虑,同时也会述及对应的业务特性。

业务特征

目前存在的企业软件,一般是以两种形态运作的:

  • 云端 SaaS
  • 企业私有部署

通常来说,前者更侧重于通用性,价格较低,复杂度一般不会特别高;后者一般提供了各种可能的定制,但价格较高,可能会有非常复杂的形态。

价格是企业选择软件的一个很重要因素,所以我们能看到,很多客户在选择软件的时候,对功能点的选择非常精细,有时候不得不舍弃一些相对次要的功能,而且,他们常常会抱怨软件实在太贵了,也并没有那么好用。

另外一头,从软件开发商的角度看,需要尽可能避免一次性的定制需求,需要努力把它们复用到其他客户那里,以此来摊薄开发成本,所以,会需要从各种角度去提高需求的复用率,降低一次性开发成本。

从刚才提及的两种部署形态来看,都有一些问题需要解决。

云端 SaaS 模式的软件,一般会从工具属性或者行业角度入手,较好地满足通用功能,一般面临的问题是可定制性。用户往往借助垂直能力,或者是通用行业模板,解决了自己的第一步问题,但随之而来,就会有更多的诉求:

  • 我有一些需求,需要更多地对现有的系统进行定制,如何去做,谁来做?
  • 我想要新增一些需求,这些需求当然也可以通过购买其他厂商的 SaaS 服务来达成,但与现有系统的整合就是个问题

中小企业在成长过程中,不可避免会需要这些诉求,SaaS 系统应当有随之成长的能力,这才是不掉队的本质。因此,当侧重于工具领域,比如:IM、协同、知识库等体系的 SaaS,其后必定需要开放很大程度的开放与定制能力,要不然,多系统集成一定会成为一个巨大的瓶颈。

我们可以参照电子行业的发展来看待问题:

几十年前,市面上存在很多各类专用设备,比如说,导航设备,那时候会有不少厂家,定制一个小的机器,然后在其上跑专用的软件。用户为这个功能所支付的价格,实际上是软件加上这个硬件的总和。再比如,数码相机,它仍然会需要有一个机器,尽管用户所需要的只是其拍摄、预览与存储能力。

现在来看,这类设备的销量大幅下降,因为手机这样的通用设备的能力得到了增强,硬件部分被合并同类项了。

那么,我们可以问自己一个问题,软件也会这样吗?

软件的同类项是什么?

是 IaaS 吗?
是 PaaS 吗?
还是?

我们是否应当为业务之外的附属基础设施,支付重复的费用呢?

回头再看企业私有部署系统,通常面临的问题就更多一些,但大部分问题都是在下面几个方面:

  • 价格
  • 需求沟通
  • 变更速度

私有部署软件价格高的原因有两个方面:需求复杂,开发代价高。需求的复杂是不可避免的,这是业务方的原生复杂度,而需求的沟通反复,则往往成为此类交付的核心痛点,与之相比,连耗费巨大的定制化开发过程都不可避免地成为其附属环节了。

几乎所有这个领域的软件交付厂商都很早就采用了大中台,小前台的作战方式,然而在实践过程中,仍然会因为前台部分过重,中台部分难以很实际地对前台产生帮助,形成一种非常尴尬的局面,最终导致双方的互相不信任。

我个人认为,这个问题的症结在于中台支撑能力的偏弱。传统意义上的中台支撑,其技术化程度较高,往往是提供各类中间件、组件库、约定研发模式、构建发布、持续集成等等底层能力,但是在另外一件事情上做得不够远,那就是业务描述能力。

什么是业务?如何描述业务?

谁有业务抽象能力,谁就会赢得下一轮竞争。这个竞争的关键,一定不是因为你提供了多少种中间件,多少种组件,那些只是底层可扩展的能力。

中台能力

所谓中台能力,不仅是指在一家软件公司里,其中台团队对业务研发团队的支撑能力。整个一个软件公司,对客户来说,也应当相当于一种中台能力,那么,到底提供怎样的能力才能有助于各行业的发展呢?

很可能一线互联网公司的研发人员还是很难理解其他一些公司的痛点:

  • 自身不是软件公司,没有 IT 团队
  • 即使有 IT 团队,也很难有支撑大规模研发的能力

这其实是个很难的问题,先不说多数公司是很难养得起一支高质量研发团队的,即使愿意出钱,也未必养得出。一家传统行业公司的平均薪资是取决于它所在行业的,大部分行业都达不到 IT 和金融的收入水平,他不愿意付出媲美一线互联网公司的薪资就会招不到人,他愿意付出这个薪资,就会导致自身企业中的一些意见,人性大抵如此。

因此,很多公司的软件都面临一个问题:

  • 业务变更了
  • 老系统不能满足需求
  • 要么凑合用,要么自己的 IT 人员能够适当定制,要么发起采购,找软件公司来定制
  • 采购流程过长,一次大型交付耗费了一年多,交付的时候业务形态跟采购的时候又发生了变化……

这个过程是非常痛苦的。如果把软件公司自身作为中台,其核心价值应该在两个方面:

  • 能快速落地业务
  • 能支持业务的快速变更

当这两个能力比较好的时候,需求变更所造成的反复成本就可以缩小,业务方,无论是自身业务,还是客户那边,都更加有机会去把 IT 系统尽快调整到适合自己公司的业务发展需要上。

技术细节的屏蔽、可扩展性的支持,对这两者的权衡,将成为技术中台成败的关键因素。

开发技术

作为软件形态的一种,企业软件除了共性的问题,比如需求的正确实现,一般还需要重点考虑以下几点:

  • 开发成本控制
  • 差异化需求管控

这几点,几乎是影响大部分企业软件生死存亡的要素。所以,通常会需要在自身的研发过程中,去产生各种各样的快速研发、需求分支管控方案。

前面我们提到,对业务的描述是一个核心竞争力。为什么呢?

因为几乎所有软件企业,都不会希望自己做的东西是一次性的,都希望能沉淀,并且尽可能作为一种平台能力,交付给其他客户使用,以达到同等成本下,盈利的最大化。

在面向行业的交付领域,我们一定能听到这样的描述:给客户甲提供的某某功能,客户乙也想要。他想要,怎么给呢?

传统的研发管理,其分支是基于代码的,代码实际上是一种很底层的抽象,尤其因为跨越了多个不同技术栈(服务端、Web、客户端),导致很难去描述:这个需求改了哪些地方,也就因此,很难去描述业务的增量与合并。

所以,在不同项目、不同分支之间迁移需求,对研发人员来说,是一个非常苦闷而麻烦的事情,这也就是“描述业务、解释业务”的意义所在。我们需要把业务描述成一种线性的东西,去除抽象细节,可以升级,可以 diff。

对业务的抽象,除了有助于研发过程,还可能让懂得业务的人员参与,甚至拉动客户侧的一线人员,共同参与改造升级自己的业务过程。从一个大的角度去看,中台定制能力的低技术门槛化,必定是一个长期趋势。

人员分工

当前,一个有意思的问题是:在你心目中,按照角色划分,企业软件前后端开发人员的比例应当大致是怎样的?

最近几年被谈得很多的一个名词是“前后端分离”,处于不同场景的人对它做出了不同解释。虽然在分界、实践路线上各有差异,有一个共识是:这意味着前后端工作职责的分离,前端去处理偏展示的部分,后端侧重于存储和服务相关的逻辑,两者通过某种基于接口描述的约定来协作。

在企业软件领域,有很大一部分应用至少十多年来都一直就是这么协作的,大部分把分界点定在 HTTP 请求这个位置,这是一个比较天然的分界,两侧的代码执行过程分别位于浏览器(或者广义的各种端上)、服务器。

前后端的职责分离,有时候又会带来协作上的麻烦。大部分的业务,无论前端还是后端,复杂度都没有到很高的程度,如果职责分离所带来的协作成本大于同一个人,往往就不如“全栈”。

全栈是一个筐,什么都可以往里装。通常这么一个全栈业务开发人员,需要同时有两种不同的开发和构建环境,有各自的包管理机制,编程语言和范式。虽然他的职责专注于业务实现,可是常常要在不同的工作上下文中切换,包括编写不同模块(前端,后端)所导致的思维方式的转换,而工具复杂度往往也造成了一定程度的困扰。从协作关系来说,我们应当想办法降低至少一端的工程复杂度。

全栈并不是只有全部使用 JavaScript 开发这么一个选项,这只是一种可能的方式:我们选择了把后端轻量化。但与之相对,也有一种把前端轻量化的方式。

多年来,人们尝试以不同的方式编写视图,有一种东西叫做 GWT,业务开发人员使用 Java 来编写视图代码,然后构建之后,生成 JavaScript 在浏览器中执行,这也是一种实际能够运作的机制,在某个时间段可能是异端,可是:为什么我们能够接受用 TypeScript、CoffeeScript、Reason、Elm 去编写 Web 视图,偏偏就觉得使用 Java 很奇怪呢?

语言并不是我们需要重点关注的东西,我们还是把目光投向视图本身。

即使是今天,我们仍然可以看到一些很奇特的东西流行着,比如 layui,在很多前端眼中,这是一个很过时的东西,然而,这并不影响很多开发人员选择它,而且,用它来开发业务,似乎效率也没有低很多。

这可以说明一个问题:在存在大量封装组件的前提下,具体在使用哪套技术栈开发,其实对研发效率并没有实质性影响,提高研发效率的东西是组件库,而不是某种具体框架,因为在存在约束的前提下,业务开发人员实际上只使用了这种框架一个非常小的子集。平台侧的技术人员所需要掌握的各种细节能力,业务开发团队并不一定需要全部掌握。仅仅写个 CRUD,就需要懂得各种编程语言底层理念甚至范畴论,这很明显是有问题的,这类方式也因此不利于周边生态的发展,对于阿里这类尝试连接天下的各种行业大中小企业的生态核心企业,其严重程度很可能远超想象。

为什么 VueJS、微信小程序这类东西,大家都认为技术细节上存在许多可改进的地方,然而其用户群体却一再增大到难以想象的程度,一线互联网公司的精英派开发人员跟这个社会的大环境到底存在多大的隔阂,为什么中国共产党从农村起家,最终击败了精英派的国民党反动派,其原因值得深思。能让多少人参与进这个事情,很可能才是决定走到多远的关键因素,我们没有理由放弃社会中的每个人,仅仅因为他不能很快学会你熟悉的技术栈。

所以,长远而言,如果我们拥有了描述业务的能力,则研发过程的细节都是可被抽象,可被在底层升级的,这不是每个人都需要去关心的事情。我们现在用手机,并没有几个人去关注它的 CPU 集成了多少个元件,屏幕上一个像素点到底由什么东西组成,它们都被抽象掉了。

另外一个方面,开发方式也需要考虑成本。交付型项目的盈利很大程度上取决于成本控制,一线互联网公司的开发人员普遍是意识不到这个问题的,因为本质上他参与的研发项目是不计成本的,他不需要去关注人员的薪资,上下游环节配合等相关的成本因素,但在交付领域,这些全都是问题。

推而广之,业务软件的研发流程也是一个很可怕的事情。当我们面对一个业务的时候,按照一线互联网公司的通常做法,会发现流程是非常长的:

  • 产品需求
  • 原型
  • 交互和视觉设计
  • 后端 + 数据库
  • 前端
  • 测试

在此过程中,一旦产生变更,则基本上要涉及全流程的每个人,其沟通代价是阻碍高效交付的核心问题,所以,在业务侧的全栈化必定是一个非常重要的事情,否则成本无从控制。这些角色中,最好只存在产品 + 研发两个大角色,甚至在轻量业务中,借助平台能力,让二者进一步合并。

收拢角色的前提就是,每个环节需要砍掉过于灵活的可定制性,这个过程非常痛苦,并且非常考验抽象能力,但在大的生产过程中,则是非做不可的事情。

我们能给业务侧提供什么样的能力,这是平台侧研发人员需要时刻思考的东西,不要强求他变成你这样的人,才能用你的东西,要时刻从全流程的角度去看问题,找到阻碍生产力提升的地方,并且去改造它。

设计体系

我们谈企业软件领域的前端,就绕不开设计体系。一直以来,企业软件领域的设计风格都以丑陋、风格过时等缺点广为诟病,谈及这个问题的时候,就需要阐述这么一个答案:企业软件领域好的设计风格到底应该是怎样的?

近年来,我们可以看到以蚂蚁 Ant Design,阿里 Fusion 为代表的,包含设计理念和组件库的一体化方案,各自的主打也都是企业级产品、中后台领域,那么,它们会是这个答案吗?

前不久有一篇文章,对比了 Ant Design 与 SAP Fiori,这篇文章的结论我很不认同,并不存在两者相比谁更优秀的问题,而是两者目前并不处于同一个维度上。

企业软件领域的设计体系,在我看来应该包含以下部分:

  • 表层部分
    • 布局相关的约束(包括响应式、在各端上的体现)
    • 基础的数据输入项(各类表单组件)
    • 布局容器与导航
    • 多维度的数据展现(列表、树)
    • 各类图表
  • 隐含的约束
    • 对于可访问性的指导,包括快捷键等
    • 操作记录的维持(表单的草稿,列表筛选项的缓存,自定义表头的缓存)
    • 统一的信息流
    • 默认的可访问性
    • ……

我们能够看到,互联网企业推出的常见的设计体系,往往都在场景上比较固化,很侧重并依赖于单个:搜索+列表+表单 的场景,对于更复杂的组合,或者是高度集成的单一视图,则缺乏指导性。

从逻辑上讲,因为一切视图背后隐含的逻辑都是数据库表操作,都可视为单表 CRUD 的聚合,或者是包含了事务的这些 CRUD 的组合,那么,如果不介意思维上的关联,我们大可以用单表管理的方式描述一切业务,或者稍复杂一些,使用主从结构的视图来管理一对多的关联表。

这个逻辑,是目前市面上存在的一些产品的理论依据,比如说 airtable,它就围绕对单表操作的各种形态,以类似 Excel 的操作体验去完成各类业务系统的定制。

我们目前所能看到的各类管理系统,出于降低开发者心智成本的考虑,很普遍地使用了这样的设计,所以大家的界面千篇一律,一切业务都是一个管理控制台,每个页面所呈现的东西都比较有限,除了聚合的 Dashboard,一般界面上放三到四块东西就结束了。

需要注意的是,尽管这样开发出来的系统,从整体感上已经不错了,但整体体验应该也就是在及格线上。为什么呢?因为前面我提到,这降低的是开发者的心智负担,而不是使用者的。

从业务使用者角度看,他们可能存在很多诉求:

  • 在关联实体之间,有侧重点,需要突出最关注的实体,把另外一些东西作为它的附属
  • 对于同一种业务的视图形态可被灵活定制
  • 作为一些特殊角色,每天的工作高度依赖于某几个具体界面,期望有足够的信息密度,尽可能优化常用业务的触达路径

业务系统设计上的难点在于:

  • 业务设计语言的设计者,通常离业务有一些距离,所接触到的业务多半是容易理解的简单管控系统,而一旦有内在业务逻辑很复杂的系统,则需要长时间深入才能得到一些体感。
  • 业务系统中的共性,是很难提取的信息,需要长期深入多种不同的系统才能发掘。

我们再回头来看之前提到的 Ant Design 和 SAP Fiori 的对比,会发现前者在一些细节上面有明显优势,但体系化方面则跟后者存在较大差距。

所以,如果从一个大型企业角度,整体看待设计体系,会要求更多的一致性,并且,在业务上提取更多的通用准则,这些准则可能是严格的,而不是倾向于宽松。

比如说:

某个数据表格中,行内有“修改”、“删除”这类的按钮,这个按钮的大小,什么行为的按钮应该是什么颜色,都需要去做约束,而不是任由开发人员发挥。

一个用于承载业务的中台体系,如果不收敛其设计规范和前端组件,则必然导致研发流程的反复性增加。

总的来讲,从设计形态上看,倾向于“约束”而非“发挥”。而在清晰定义并描述了这些约束的前提下,很多能力应当成为默认拥有的。防止出现不符合设计规范的东西出现,提供无需额外配置就默认达到 60-80 分体验的能力,这才是业务设计体系的实质。唯其如此,才有可能精简从产品到研发中间的环节。

前端架构

不适应业务的架构是失败的,作为工程与架构管控者,需要时刻思考在自己所处的环境下,存在什么痛点,什么环节,人员结构如何,主次矛盾分别是什么。

前端这个角色,受开源技术体系的影响太大了,很少人意识到:很多工程体系、库,都是需要被整合了再使用的。其整合方式取决于整个研发体系的业务形态与人员结构。

作为前端,可以尝试问问自己这些问题:

  • npm 是一种适合被非专业前端(泛指,可能是其他技术能力很强,但未深入现在前端工程体系的人)直接使用的东西吗?
  • 每个人都需要去定制“业务组件”吗?
  • 业务开发人员一定要“构建”前端项目吗?
  • 在 CRUD 项目中,Redux 这类东西是不是需要被显式感知的?
  • ……此处空间太小写不下了

具体到企业软件前端领域,总的来说,可定制性会是一个很重要的方面,有一些可以关注的方面:

视图特征

企业软件视图层面的几个基本特点:

  • 交互模式固定,可穷举
  • 对低成本的快速开发机制有较强需求
  • 交付模式导致业务差异化的配置需求多

基础组件库

一般来说,组件库是大家都会注意到的技术依赖项,它在构建一个大型软件的过程中,几乎是必不可少的,不同的团队拥有对组件库的不同控制力度:

  • 自己有能力实现整套组件库
  • 能在开源组件库的方案基础上作自己的定制
  • 能整合不同的开源组件库

在这里,组件库的实现技术并不算特别重要,更重要的是对业务场景的覆盖程度。

业务组件

前端团队很容易对“业务组件”这个东西产生盲目而不切实际的追求,实际上,在企业领域,绝大部分“业务组件”是没有价值的。鲁迅先生教导我们:

其实地上本没有路,走的人多了,也便成了路。

这就好比是我们企图抽象一个大粒度的业务组件,给外界开了一些配置项。

但久而久之,配置项越来越复杂,比组件自身的内部实现还复杂了。

走的人太多了,处处都是路,又没有路了。

视图其实是:Model - ViewModel - View 的最外延,每一层的灵活程度逐次增加,自身其实就可以视为一种配置文件了,在配置文件里抽组件,很可能是性价比最低的事情。

前端需要把视野往全局去放,才能在这个事情上找到更合适的权衡。

工程设施

时至今日,前端已经有了相对“正式”的开发环境,我们可以基于更先进的语言特性、更强大的工具去构建组件库或者业务视图,这些都是工程设施的重要组成部分。

然而,现在主流的前端构建体系,不一定非常适用于企业软件研发这么一个受限的领域。大如阿里的某个大部门,其 Web 系统数量可能上千,而公共的直接依赖项则未必过百,每次构建都要带着这些东西一起处理,对容器集群来说是不是一种巨大浪费,值得深思。

依赖管控

随着现代工程设施的引入,前端有了更明显的依赖管控机制,这个事情是一个双刃剑,一方面能得到更强大精确的依赖控制机制,另外一方面,引入了一些管理复杂度。

与构建相关的事情综合考虑,究竟是不是存在一个“公共基座”的东西,让业务方无需关注这么细节的组件版本升级、关联构建等机制,都是可以去探索的。

此类事情可能很多,其大的原则就是一个:开源技术栈应该经过怎样的定制和管控,给什么样的业务开发人员提供怎样的抽象程度?

小结

在我看来,一家理想的软件企业,其研发管控能力的分水岭应当是:能否升级自己 3-5 年前给客户交付的系统。这个事情非常难,但如果不难的话,又怎么会有机会呢?工程师的实质就是在给定的资源条件下,寻找目标的最优解。

天生我辈,自当无惧其深,不惮其远,上下而求索。阿里有句老话:路走对了,就不怕远。