前端与数仓可以实现“无壁”沟通吗?

豆皮范儿的小伙伴们大家好,今天我们带来了与经常与数据打交道的数据仓库,作为技术不舍边界的字节同学,我们前端同学也会去理解和深入业务,可以很好的理解整个数据链路,才能更好的做好每一个数据产品。

本文作者:小隐同学

前言

大数据时代对前端的赋能绝非仅为“从后端接口获取数据,然后以一定方式展示在页面中”而已,前端从事人员被给予越来越高的期待。尤其是当你正在一个数据平台类的公司或部门乘风破浪,那么对整个数据链的了解,甚至一个人cover整个链条,都可能成为常态。

一、在数据平台,一个前端要做好的心理转变

如果你被问到:“前端与数仓如何实现交互”?你将如何给出答案?

如果是之前的我,我会说,前端是与后端直接交互的,而与数仓间接交互。

评审-> 需求分析 -> 前后端约定接口文档 -> 开发 -> 前后端联调 & bugfix -> 测试回归 -> 上线

在上面的流程中,前端最重要的工作就是将后端传来的数据“妥善安置”,久而久之,便成了无聊的“数据搬运工”。当然,这样的想法,很容易让我产生对前端意义和乐趣性的怀疑。

而前端与数仓,似乎是隔了后端这一层“壁”的。像数仓做了什么工作,当前需求涉及的口径都有哪些,分别是什么含义,原始数据库表中都存了什么,没有注意过。数仓对于前端,仿佛是一片“灰色地带”,至于前端与数仓直接沟通?从未尝试,从未思考过。

在数据平台部门,每个人必不可少的就是与海量的数据打交道。

作为入职不久的新人,我逐渐意识到,前端不能甚至不允许仅仅关注后端传过来哪些字段,此外还需要花一定的时间,去关注整个“数据链条”。从数据底表存的是什么,字段含义,表之间如何经过抽取、拼接、计算生成了最终取数的一张“大宽表”,经历了怎样的例行任务,前端最好都要了解一下。

为什么?

因为在了解了这些数据的含义之后,才能开发过程中发挥火眼金睛、一目了然的能力,把出现的不合理数据,及时地反馈给后端、数仓。以前端角色发力去推动项目的进程,这也正是一种owner意识的体现。这样有意识的锻炼,对于前端来说,不仅能增加数仓方面的能力,甚至可以增加一部分的数据分析师的基本素养。

二、前端数仓的“去壁化”方案

1. BFF层作为服务端

xx项目开发的启动,因为后端人力不足而一再推迟,成为我们进行跳过后端服务器的前端数仓的“去壁化”方案探索的一个契机。

首先,我们研究了当前部门成型的开发模式。借助部门已有的几款优秀的数据产品,数仓同学和后端同学可以分别在不同的平台上进行SQL语句验证、数据同步、接口取数等基本操作。前端参与的环节仅有对接口和向后端服务请求数据。

当没有后端服务时,前端如何与数据直接产生交互?

此时首先想到的是,node赋予前端的更大可能性。众所周知,node的出现,让前端开发既Ajax之后,有了全新的面貌,在开发效率,性能等层面都有质的提升。

使用node作为服务端,即BFF(Backend for Frontend)层,是为前端服务的后端,是各种端(Browser、APP、miniprogram)和后端各种微服务、API之间的一层“粘合剂”。BFF层主要的业务场景大多数是请求转发、数据组织、接口适配、权鉴和SSR等聚合型的业务场景。

如果将后端服务替换成用node开发和维护的BFF层,则基于原有的开发模式,将出现下图所示的一种新的开发模式。

在新模式的流程当中,数仓同学写SQL并在DataWind平台查询验证通过之后,则可以将数据集导入数据服务平台,根据sql和具体参数等生成相应API。此时工具或者微服务等工具化/自动化的辅助工具,可获取基于数据服务平台对应的SQL和返回的数据结果,同时基于查询的数据结果解析成对应的Schema中。生成的shcema会导入到BFF层服务中,前端可根据schema知道有哪些数据,数据格式的结构等信息。

同时,对于一些较为轻量的数据库操作,BFF层可以借助ORM框架,直接进行Mysql库上的CRUD。如果项目后期开始接入较为复杂的数据库操作,或者数据获取的纬度多元且非常复杂,则可接入后端,对BFF层暴露接口。

因此,新模式具有以下明显优势

1.前端人员上手node较快,前后端工作仅由前端同学负责,可以有效降低人力成本。

2.前端因为直接和Node层服务进行交互通信,同时可通过有效提高开发人员的开发效率,有更多的可能性。

3.采用工具化/自动化的方式,可以有效降低因复杂类型的数据而产生的前后端沟通协同成本,明显提高开发效率。

4.可随时接入后端服务,Node层可发挥更多功能。具有较高可扩展性。真实后端接入后,可更加聚焦于模块化功能开发,而非聚焦于UI功能开发。

5.利用DataRocks平台查询数据的能力,通过工具/平台与Node中间层服务打通,降低后端同学的数据搬运成本及前后端对接数据的协作成本。

2. GraphQL:一种用于API的查询语言

前面提到,不管是BFF端,还是真实的后端,我们希望服务端可以面向模块开发而不是面向UI开发,即根据不同页面所需要的数据进行不同接口的开发。服务端可以一次性定义完所有功能,而不需要逐个开发。

服务端实际返回的数据,由前端来指定的,即“Ask for exactly what you want”。这是一种提高开发效率,节省沟通成本的方式。另外对于前端工程师来说,可以在BFF层使用一种更容易上手的查询数据的API方案,从而降低学习成本。

因此在API设计上,我们选择了GraphQL:一种用于 API的查询语言。

所谓“Ask for exactly what you want”,总共分几步?

首先,强类型的schema。指定了接口返回字段的类型以及数据结构;

type Project {
  name: String;
  tagline: String;
  developers: [User];
}
type User {
  id: Int
  name: String
}

其次,query表示你要请求的数据,比如此时你只关注tagline和开发者的名字;

{
  project(name: "IM-GameBI") {
          tagline,
    developers {
      name
    }
  }
}

最后,得到可预测的结果。结果按照你想要的数据及结构返回。

{ "project": {
    "tagline": "A game intermodal project"
    "developers": [
       {"name": "wangning.front"},
       {"name": "wuhongjiang"},
       {"name": "zhangkun.fe"},
    ]
  }
}

优势1:GraphQL API基于类型和字段的方式进行组织,而非入口端点。你可以通过一个单一入口端点得到你所有的数据能力。因为强类型的Schema,GraphQL保证应用只请求可能的数据,还提供了清晰的辅助性错误信息。应用可以使用类型,而避免编写手动解析代码。

优势2: 相比于典型的REST API请求多个资源时得载入多个URL,GraphQL可以通过一次请求就获取你应用所需的所有数据。这样一来,即使是比较慢的移动网络连接下,使用GraphQL的应用也能表现得足够迅速。

优势3:使BFF层维护代码的成本较低。GraphQL API字段和类型的新增和废弃,不影响现有的查询,可以更好维护的服务端代码。

新模式引入GraphQL后的角色及多端交互的细节如下图。

三、“去壁化”方案的自动化探索及落地

GraphQL在API不需要频繁变动版本时将发挥其最大的优势。一旦API版本频繁变动(如项目启动前期),则需要开发者手动维护大量的Schema的变更。

在实际开发中,我们发现,如果Datarocks中的某个API返回的内容发生变化,则Schema需要及时得到更新(字段的增删改、数据结构的变化),同时请求数据的query也要随之变化。这是“牵一发而动全身”的效果。反复修改Datarocks API、Schema、query以及前端的各种type限制,实际上拉低了开发的效率。

因此自动化方案必须提上日程。自动化的目标大概如下图所示。

1. 工具链

  1. @dp/open-api-auto-tools:基于Datarocks的接口动态生成OpenAPI文件(oas.json)的Cli工具。开发者调用命令时,需要经过sso鉴权。
  2. openapi-to-graphql:将DataRocks的OpenAPI规范转化为GraphQL Schema。
  3. @dp/byted-gulu-graphql:集成openapi-to-graphql,实现鉴权、自动生成Schema(可含自定义Schema),并将其挂载到app实例上。
  4. @dp/graphql-codegen-util-plugin:集成了graphql-code-generator实现将query转化成对应的各模块query,以及接口类型、参数类型。

构建自动化工具库,实现自动地生成用于类型检查地ts文件、GraphQL Schema等,解放双手,提升开发效率。经过自动化后,BFF端代码几乎无手动输入代码,若Datarocks OpenAPI发生改变,BFF只需要run一遍脚本重新生成oas文件即可;前端无需手动维护类型文件,仅需按照后端接口调用模版请求数据即可。

2. BFF层自动化流程

![](https://tech-proxy.bytedance....

3. 前端自动化流程

![](https://tech-proxy.bytedance....

四、展望

目前我们所围绕着是通过BFF层,作为承接数据端和前端的桥梁,而最终我们想要打造的是,通过不断演进和丰富的数据服务BFF层,与数据组件市场两者结合起来,能够进一步地将数据的能力进行泛化和下沉,使数据平台所生成的中台数据能力能够更快速、更便捷的被第三方平台使用和接入。
我们也在积极的在这一方面进行探索,相信未来不仅能够提供“数据服务”,更可以通过“数据组件集市”的方式为大家提供另外一个维度的服务。

五、结语

以上就是 前端与数仓“去壁化”沟通的一次实践,也是GraphQL落地在真实项目中的一次尝试。已经验证了方案的可行性,并且在实际项目中成功落地。

现阶段GraphQL还属于新鲜事物,很多技术细节仍然值得探索和验证。比如它的复杂性较高,它用用来权衡比如缓存这样棘手的功能,因为GraphQL没有像REST API一样重用HTTP缓存语义。随着业务的扩展,我们对此开发模式的探索也将越来越深入。

也欢迎大家使用这一新模式展开探索,一起讨论和学习。

参考

  1. Nate Barbettini - API Throwdown: RPC vs REST vs GraphQL

The End

你可能感兴趣的