DDD系列之"BFF架构"

技术 · 07-10

不管是通过DDD方法论设计新服务还是梳理老服务,绕不开的一点就是接口设计。接口设计时很容易犯的一个错就是经常会根据接口调用方的个性化场景(比如多种界面展示)设计出很多类似且重复性的接口,且接口的实现逻辑割裂、复用性差。为了让业务服务更加聚焦领域能力,根据领域能力设计对外接口,同时又要满足多样化的接口消费场景如前端展示,架构里往往需要引入BFF这一层。

在用户体验至关重要的今天,程序展示界面丰富多样。比如同一个界面可能同时存在极简版、专业版,一个界面要展示多种数据,要连接的设备也层出不穷如小程序、APP、网页、客户端等等。归纳起来有这几类:

这些需求如果都在前端完成,则前端需要多次网络请求服务端数据,并且接口相关的适配逻辑不适合用前端技术来处理,效率不会高。但是如果一股脑丢到服务端来处理,则服务端模块的接口频繁修改带来稳定性下降。模块界限会变模糊,接口数量膨胀厉害。展示逻辑和领域逻辑混杂在一起,久而久之业务逻辑将变得难以维护。

从DDD角度看,提倡围绕领域业务能力进行接口设计,服务端应该聚焦领域自身能提供什么样的能力来设计接口,而展示相关的处理逻辑不应该是领域业务。因此可以得出这里的主要矛盾是前端的本质是提供良好的用户体验,必然会高频迭代,而服务端的业务逻辑和关键业务数据字段有行业特性,相对比较稳定,不会随着体验变化很大。那应该怎么办呢?

既然错不在前端也不在服务端,那么一般架构的做法是引入新的一层。业界的叫法是BFF(Backend For Frontend),即后端为前端编程。BFF源于Sam Newman在微服务模式里提出。BFF其实也是微服务架构下的产物,通过引入BFF解耦了前后端,也对组织架构做了归属和指导。下图来自他的BFF文章:

增加一层永远是解耦的大招,但BFF只是逻辑分层的名称,不是具体的技术。实现BFF的技术框架有多种。从BFF层的组织架构归属看,由前端团队或后端团队负责则会引入各自不同的技术选型。前端有NodeJS、GraphQL框架等,后端有Java、GraphQL框架、网关框架等。因此很多大厂的产品都有BFF层,但具体的实现各有不同。不妨来看一下BFF技术要考虑的4个方面的关键诉求。

康威定律是架构首要考虑到的,前端模式或者后端模式会决定BFF由不同技术栈的团队来承接,也直接影响着BFF层的技术架构演进方向。相应地这两种模式各有优缺点。但不管是前端团队来承接BFF还是后端团队,没有对错,应该根据组织自身的现状和发展来思考。

即消费方每次都必须按照接口供给方规定的请求参数发起请求,获得请求出参数据。

从上面两点来看其实编程语言不是关键。如果业务和团队规模不是很大,建设BFF层到这里就够用了。但一旦业务和团队规模变大,展示和取数逻辑涉及的团队人员和接口数量激增,如何高效地完成重复性的接口开发和取数调用将变得关键。突破口往往都是某种意义上的元数据驱动。做到声明式的接口开发体验效果。

因此BFF层的建设将分化出底层框架开发和业务开发两类工作。业务开发以类似DSL(领域专属语言)的方式(比如XML/Json表达、甚至界面拖拽形式)定义出需要从哪些接口取哪些数据字段,做哪些数据加工动作。底层框架负责以标准化的步骤实现接口的定义、组装和调用。

即消费方可以在调用接口时表达自己想使用哪部分数据,从供给方获得按需的出参数据。通俗地讲就是消费方调用同一个接口时可以控制接口的出参数据。

按需查询的能力听上去很好,但实现的成本也高。因此需要深入理解产品和业务的形态,先回答到底有没有这种需求,值不值得去支持。

这个问题关系到BFF服务在整体架构里的定位。在没有BFF之前,微服务架构里一般都有一个反向代理层,即负责路由和转发来自外网的http和tcp请求给内部的微服务集群,也起到了不把微服务对外暴露的作用。同时可能还会有API网关这一层,负责对接入层的请求进行鉴权、协议转换、流量控制等。相当于把每个微服务要做的事情集中做一次。如果引入BFF层,需要考虑和API网关的职责和协作。

上面提到的GraphQL服务端也有鉴权和流量限流的设计,甚至还有普通微服务的数据库访问的设计。因此BFF层的定位要清晰,要想清楚BFF服务仅仅是微服务接口的聚合层?还是叠加了API网关功能?还是一竿子到底的全栈微服务?

BFF服务作为服务端的一份子,必然需要考虑如何无缝地融入现有微服务架构,满足微服务的横向非功能需求。包括:

根据上面提到的关键诉求满足程度以及当前业务发展情况,笔者结合自己经历过的项目实践以及了解到的其他团队的实践,把BFF服务能力划分为如下几个不同层次。方便你根据团队和业务现状进行BFF技术选型和建设力度的决策。

前面多次提到了GraphQL,下面笔者结合经历过的一个生产项目实践来聊一下GraphQL的落地细节。为什么需要建设BFF这一层就不多说了,因为是ToB项目,界面展示逻辑普遍复杂,产品同时支持浏览器、App、小程序、M站等

举例来说,下方CorpWechatQRCodeDetail是一种对象类型,包括数据格式和对应的查询接口。

前面都说了BFF和GraphQL的优点,下面说下缺陷部分。

微服务DDD化后需要尽可能地保持领域模型和领域接口的纯洁性和稳定性,如何应对多样化且高频的前端展示需求是一大挑战。引入BFF是一个解法,但架构需要权衡。BFF服务的存在本身有利有弊,BFF的不同落地实现也有利有弊。GraphQL听起来很炫酷但也不尽然。实践能出真知,但对所支撑业务的理解也很关键。很多时候还得回到业务和团队中去看。

本文作者:小码哥

本文链接:https://www.wesee.club/archives/991/

版权声明:自由转载-非商用-非衍生-保持署名(cc 创意共享 3.0 许可证

Theme Jasmine by Kent Liao

粤ICP备2023052298号-1