原文链接: Conversational Tech, Domain-Driven Design, and Microservices (翻译:吴鹏 微信ID:wupeng1127)

译者介绍

我叫吴鹏。这个世界有很多人被困在无聊琐碎重复的工作上,我希望利用AI技术上人们这样的工作中解放出来。我是一名AI应用工程师,目前正专注于让机器从文档中抽取结构化信息。

看看微服务和DDD在对话式应用中的是怎样结合在一起的

社交媒体、金融技术和整个数字经济的出现都是由技术超前推动的——这已经不是什么新鲜观点了,但问题是,现在的技术正在变得(并且愈发让人觉得)越来越人性化。在诸如Sophia和波士顿动力的Atlas等先进的人工智能系统中,你可以看到更多的这种拟人技术的进步。尽管这些都是极端的例子,但在我们身边的、与我们的日常活动有直接触点的常见的技术也正在变得更加对话化——例如,即时消息、聊天机器人、物联网,以及Siri和Amazon Echo等个人助手。

在主流的类人AI实现之前,对话式技术领域的巨头是社交媒体和即时通讯平台,其中至少有一个平台拥有27亿用户(约占上网人数的75%)。预计2021年这一数字将增长到38亿,占世界人口的50%左右。

对话式技术对我们的生活和习惯的的影响之巨大,再怎么强调也不过分。研究显示,智能手机用户平均每天花在手机上的时间约为5小时,其中90%的时间花在社交/通讯应用上。不需要天才就能推断出,我们生活的大部分已经变成了由社交触发,变得数字对话化,并且越来越习惯。MeToo运动和Cambridge Analytica系列事件的出现,更进一步地揭示了,对话式技术现在是多么深入地根植在那些关于我们是谁和什么影响我们的大量的定义当中,同时它也是提供即时满足的一种渠道。

就拿金融技术领域来说,虽然对话式技术还需要迎头赶上,但它就是未来。越来越多财务相关的对话发生在社交平台上(与其他领域一样);这些对话在社交平台上开始,却在别的地方完成。例如我们很容易会说“嘿,Bob,我要给你发20块昨天的晚饭钱,没错吧?”然后暂停对话,在Zelle或任何其他移动银行APP上完成交易。倘若交易能够在当前对话的环境中完成,这样会更有意思······Bob回答“是的”然后钱就自动地从你的银行账户转到了他的账户,不用额外的点击或者说明。或者,想象一下,用Finie这样的财务助理来完成这笔交易。

显然,金融服务的未来将是对话性的,并将吸引越来越多的数字原住民(从出生开始就熟悉信息技术的人)。 这些服务将会直接输送到他们的习惯中去,在客户花费时间最多的地方满足他们的需求——这就是我们构建mTransfers的原因。

mTransfers是一款利用手机键盘在社交媒体对话中提供金融服务的银行应用程序,它最初是在没有专用后端的情况下构建的,完全依赖金融机构的核心api。一开始采用这种模式主要是考虑尽快地进入市场,以及隐私问题——金融机构不愿意立即让第三方访问交易数据,即使该数据是存储隔离的独立实体。

随着规模的需要,以及逐渐遵循了一些金融机构的规范,为mTransfers建立一个后端底座的时机就成熟了。Drax应运而生,它是一个基于容器化微服务的系统。设计Drax促使我们思考领域驱动设计和微服务的结合和硬边界。

最开始的时候,Drax的架构基本如下:

这篇文章将以Drax为例探讨微服务设计的思考。关于Drax架构本身、技术考虑、工具、故障缓解等会在另一篇文章中更深入地探讨。

领域驱动设计和微服务

20世纪70年代初,面向对象编程范式得到了主流的支持和使用,它基本上倡导软件组件应该以现实生活中的对象为模型,具有只能由对象本身操纵的特征和行为,并且可以通过定义良好的接口/消息与其他对象通信。打个比方,狗(对象)可以随时用腿(特征)行走(行为),但如果没有某种形式的明确定义的信息(如散步、提供零食或扔球)的话,人类就无法让它行走;面向对象编程引入了独立实体,这些实体以抽象的形式被建模为具有限界上下文的对象,并以接口作为通讯协议。

领域驱动设计不是一种设计模式,它是一套指导方针和过程,帮助我们根据业务实际做出设计决策,就像我一样,你第一次领域驱动设计时,可能会感觉它和面向对象分析设计(OOAD)的界限很模糊,但它们在很多方面是不同的。我喜欢认为,OOP在组件/原子级别上实现了领域特异性,DDD则扩展了OOP,它基于业务逻辑聚合了对象模型。

在设计微服务时考虑DDD将有助于避免出现“好”的单体服务。如果没有完全理解DDD,只是通过基于代码模块性和面向对象原则分离关注点,使用函数调用形式的“进程间”通信而不是“服务间”通信,很容易设计出一个糟糕的基于微服务的系统。例如,当你发现自己大量使用服务依赖注入时,实际上你正在处理一个模块化的单体服务。

以支付网关系统为例。如果商家服务是支付交易服务的依赖项,而支付交易服务是结算服务的依赖项,那么即使应用OOP原则,你实际上也在构建一个紧密耦合的单体服务。DDD有助于我们理解如何避免微服务中的紧密耦合,并总体上维持面向服务的架构。

在上面的Drax设计中,我们可以针对每家银行设立技术团队,有单独的发布周期、版本控制、持续集成等。随着新银行的加入,我们需要做的就是根据统一的API接口定义包装核心银行API,构建Docker镜像,添加一个服务路由/端口到应用网关或容器管理器(如Kubernetes)里面,并部署。Drax统一API定义指定了其服务的预期请求和响应方式,并使用Swagger进行文档记录。这样,我们就不需要在部署服务时更改负载或向应用程序网关层添加路由代码。通过这种架构,Drax显著地将集成时间缩短到三天。

看看下面这个设计:

这是应用DDD的一次失败尝试。这个架构的边界是基于逻辑特性的,以及基于本应该定义为动作和消息的东西。这显然会导致架构乱成一堆泥浆。首先,P2P Transfers, Bills Payment, Airtime这些“领域”不知道哪家银行将是他们的下游媒介,因此银行之间的通信模式将通过发布和订阅模式实现,引入了复杂性和可能的故障点。其次,每家银行对每个功能的理解和实现都不同,因此很难仅基于消息和参数完成交易,从而导致实体在服务之间共享或不必要地重复。第三,这一层毫无用处。这种分离应该基于OOP原则发生在实现/组件的层级上。

这种架构并没有实现DDD所涉及的全部内容,距离完美的微服务架构也还很远,我们会继续进行改进,但这是为了在微服务系统中实现硬边界所做出的一次努力尝试。

相关文章