本文翻译自PhilCalçado的官网:https://philcalcado.com/2015/09/18/the_back_end_for_front_end_pattern_bff.htmlhtml
对咱们的架构演变保持透明是咱们技术战略的一部分。咱们在无数场合谈过的但从未真正详细描述过的东西是咱们应用后端用于前端架构模式或BFF。这篇文章记录了我对如何开发和应用这种技术的理解。前端
在彻底分布式架构变得可行以前,组织一般会在一个或多个层中构建应用程序。层是应用程序的高度耦合但至关独立的组件。据加上在这,而不是服务,它被认为仅由一个应用程序使用的感受。它独立于如何不做为同一过程的一部分运行,甚至一般不在同一台机器中运行。web
让咱们用三个虚构的应用来讲明这一点,当时任何大公司都会发展出来:json
这些体系结构可能变得很是复杂,但整体而言,在不一样的应用程序之间绘制线条很是容易,清楚地划分出一个开始和另外一个结束的位置。后端
当时,每一个应用程序都有本身的数据副本和重复的常见业务流程实现。随着时间的推移,随着组织得到或构建愈来愈多的应用程序,咱们意识到咱们须要不一样的东西。咱们须要应用程序来共享数据和重用逻辑,而咱们曾经简单的架构变得有点复杂:浏览器
随着对更多重用和整合的需求,软件行业的集体思惟方式决定了一个很是抽象的概念,称为服务。实际上,这意味着上面的图表改成相似于此的东西:网络
上述架构的卖点是这些可重用服务提供的灵活性。理论上,在这个平台上构建应用程序如今是一个问题:架构
与此同时,计算机和互联网正变得愈来愈流行。过去与职员或系统操做员交互的客户开始直接与应用程序自己交互。设计思惟和用户体验研究使咱们摆脱了复杂的用户界面,专一于让专家用户更高效地得到更丰富,更实用的体验,客户能够理解这些体验 - 没有人阅读网站手册。更丰富的经验须要丰富的数据,这意味着汇总来自各类来源的信息。app
按照咱们的示例,咱们最终会获得以下图所示的内容。iphone
咱们再也不拥有业务线系统的用户界面,而是愈来愈多的用户界面自己就是应用程序。这些应用程序一般用JSP,PHP或ASP编写,其代码包含用户界面和特定于应用程序的后端逻辑。
上面简单的例子与许多现代技术组织的架构发展方式没有什么不一样。2011年,SoundCloud的网站以下所示:
Logic和All逻辑在一个地方。有一个系统,而这个系统是该应用程序。
如前一篇文章所述,咱们发现此架构存在许多问题,并决定将逻辑提取到微服务中。尽管咱们在提取后端服务方面取得了成功,但最长时间内母舰仍然处于每一个请求的关键路径上。
咱们正在进行的架构改变背后的主要动机是缩短新功能的上市时间,咱们发现咱们最糟糕的瓶颈在于任何须须触及总体的变化。考虑到用户界面更改的频率,从总体中提取代码是一种提升生产力的直观方法。而后,咱们在其本身的组件中提取了咱们的UI层,并使其从咱们的公共API中获取数据:
早在2011年,当这些架构发生变化时,绝大多数用户都在网上。正如Fred Wilson所预测的那样,最终这种状况发生了变化,咱们的用户群开始使用移动应用程序的方式比Web界面更频繁。SoundCloud已经为Android和iOS提供了很长时间的移动客户端,与咱们的新Web应用程序相似,他们直接与咱们的公共API进行了对话。
在现代软件工程中,狗食一般被认为是一件好事。在咱们本身的API之上构建咱们的产品被认为是确保咱们的API具备高质量而且始终是最新的最佳方式。在实践中,咱们遇到了这种方法的几个问题。
咱们的第一个问题不必定与技术有关,而是产品开发的根本挑战。若是咱们仅使用公共API,那么咱们的平台中没有任何内容可供第三方API客户端使用。尽管咱们想要一个蓬勃发展的SoundCloud集成生态系统,但咱们仍是一家广告公司,所以咱们须要确保人们使用咱们的属性,而不只仅是咱们的数据。建立咱们本身的应用程序独有的功能意味着咱们必须在许多地方不断检查OAuth范围,并令人们很难欺骗咱们的“官方应用程序”密钥。
在一个更技术性的问题上,咱们的公共API几乎按照定义是很是通用的。为了使第三方开发人员可以构建有趣的集成,您须要设计一个不会假设数据将如何使用的API。这会产生很是细粒度的端点,而后须要对多个不一样端点的大量HTTP请求才能呈现最简单的体验。您能够在下面看到咱们过去在总体时代提出的请求数量与咱们为新的Web应用程序生成的请求数量:
要生成该单个配置文件页面,咱们必须对不一样的API端点进行屡次调用,例如:
GET /tracks/1234.json
(该曲目的做者)GET /tracks/1234/related.json
(推荐相关的曲目)GET /users/86762.json
(关于该曲目的做者的信息)GET /users/me.json
(有关当前用户的信息)...而后,Web应用程序将合并以建立用户配置文件页面。虽然这个问题存在于全部平台上,但对于咱们不断增加的移动用户群来讲,状况更糟,由于他们常用不可靠且速度慢的无线网络
咱们在上面的体系结构中遇到的第三个甚至更烦人的问题是,即便没有总体结构,咱们仍然存在API的瓶颈。每当团队须要更改现有端点时,咱们都须要确保更改不会破坏任何现有客户端(包括重要的第三方集成)。每当咱们添加新内容时,咱们都须要投入大量时间来确保新端点不会过分专用于特定应用,全部客户均可以轻松使用它们。全部这些协调使咱们的平常工做变得比应有的困难,并使咱们几乎不可能进行A / B测试并减慢新功能的推出。
在上述架构首次亮相近一年后,咱们开始准备开发新的iOS应用程序。这是一个庞大的项目,最终会改变全部房产的用户体验。如此高风险,开发过程当中的实验和迭代相当重要。当工程团队开始考虑应用程序的体系结构时,咱们发现上述挑战将成为项目的阻碍,咱们须要从新思考咱们的工做方式。
咱们首先提出的解决方案是为移动和网络提供不一样的API。咱们的想法是,让客户拥有API的团队可让他们更快地移动,由于它不须要部件之间的协调。咱们最初的想法是为不一样的前端设置不一样的后端。BFF一词是由咱们的网络技术主管Nick Fisher创造的(我最初的建议是BEFFE,但咱们讲荷兰语的队友否决了这个选项)。
在它的第一个版本中,这些后端看起来仍然看起来像公共API,许多通用端点须要来自客户端的许多调用来呈现单个屏幕。可是,随着时间的推移,咱们发现了一些有趣的事情。以用户配置文件页面为例,之前这是一个仅存在于客户端的概念。Web或移动应用程序将从各个端点获取数据,并使用它来建立咱们称为用户配置文件的对象。这是一个特定于应用程序的对象。
在某些时候,咱们的客户团队意识到,因为他们拥有API,他们能够将这个对象推向API。他们能够提取全部调用不一样服务的逻辑,并将它们一块儿混合到后端的用户配置文件中。
这最终将简化代码并提升性能。不是对上面描述的多个端点进行多个不一样的调用,而是须要请求的全部客户端都是单个资源:
GET /user-profile/123.json
当咱们进一步尝试这个模型时,咱们发现本身在BFF中编写了不少演示模型。在这个阶段,咱们意识到BFF不是应用程序使用的API 。BFF是申请的一部分。
最终,咱们的全部属性(包括API)都开始遵循此模式。
在某些时候,咱们生产了大约五种不一样的BFF,咱们已经开始研究如何进一步提升生产率。接下来是咱们的用户配置文件示例,对咱们来讲显而易见的是,鉴于每一个应用程序都有一个等效的用户配置文件页面,全部BFF都有不少重复的代码来获取和合并它们的数据。
复制并不许确,像网络浏览器这样的大屏幕在其用户我的资料页面上的信息要比微型移动应用程序多得多。然而,咱们看到重复是一种难闻的气味,代表咱们在域模型中缺乏一个对象。为了解决这个问题,咱们建立了一个UserProfileService
处理这个重复逻辑的方法。
随着时间的推移,咱们发现了愈来愈多这样的状况。咱们开始有意识地转向一个架构,在这个架构中,用户理解的大多数核心对象都有本身的微服务支持它们。