写点什么

Marcin Grzejszczak 访谈:Spring Cloud Contract

  • 2017-04-27
  • 本文字数:3435 字

    阅读完需:约 11 分钟

Marcin Grzejszczak 是 Pivotal 的一名软件工程师。目前,他在从事 Spring Cloud Contract 的开发,这是一个消费者驱动的、面向 Java 的契约框架。为了了解该框架的一些好处,特别是消费者驱动契约对微服务测试的帮助,InfoQ 对 Marcin 进行了采访。

要点:

  • 对于架构来说,消费者驱动契约和测试驱动开发类似;
  • Spring Cloud Contract 与 Spring 生态系统集成得很好;
  • 当使用消费者驱动契约时,端到端测试变得多余;
  • 在 Spring Cloud Contract 中,Spring Rest Docs 可以代替 Groovy DSL;
  • 将来,Spring Cloud Contract 将为非 Java 用户提供改进的工具。

InfoQ:您能简要介绍一下消费者驱动契约模式以及它解决的是微服务开发中的哪类问题吗?

Marcin Grzejszczak:消费者驱动契约是一个流程,旨在帮助客户测试他们的软件,创建更好的架构设计。在架构层面,我们可以称之为测试驱动开发。现如今,软件需要能够非常快速地响应客户需求、法律法规变化及业务需求,等等。另一方面,我们 IT 行业希望尽可能快地交付可靠的软件,经过测试,不含任何 Bug。这就是为什么我们创建了部署管道——自动化发布和测试过程。至于微服务,由于架构风格本身的性质,问题被放大了。我们不可能在不影响测试流程的情况下将单体应用拆分成微服务。

单体结构中包含的复杂性被推至架构层面。消费者驱动契约试图在团队之间定义一些明确的沟通界限。CDC 的总体流程是,消费者定义他们期望 API/ 消息是什么样子。这种期望就称为契约。从这些契约可以生成存根,稍后,消费者团队可以在构建过程中重复使用它们。在生产者一端也需要验证契约。那就导致,不管是测试生产者一端,还是测试消费者一端,都需要引入一种快速失败方法。对于快速失败,我们指的是软件构建失败以及通过产品调试发现问题(例如,我们在 REST/AMQP 消息中犯了一个错误)。

消费者驱动契约将 API 设计转移给了使用它的人。典型地,服务器端的团队只需要宣布 API 会是个什么样子。通常,消费者的数量导致那是唯一可能的方式。但情况并不总是如此。我见过,有的公司没有公开暴露他们的 API,团队也不希望在 API 应该是个什么样子这个问题上进行协作。CDC 就是设法将那种方法变成一种由消费者驱动 API 变化的方法。细想一下,这很有道理。不是服务器端消费 API,是消费者消费 API,那就是为什么创建的 API 应该尽可能地适应消费者。

InfoQ:你们创建 Spring Cloud Contract 的动机是什么?你们为什么用它代替其他可选的消费者驱动的契约框架?

Grzejszczak:和来自 Devskiller 公司的 Jakub Kubrynski 一起,我们对 CDC 框架进行了分析。我们得出的结论是,它们的学习曲线很高,而且非常啰嗦。这就是为什么在 2014 年 12 月诞生了 Spring Cloud Contract 的前身 Accurest。我们已经决定引入静态类型 Groovy DSL 来定义契约。这里要说到 Spring Cloud Contract 和其他 CDC 框架的主要区别了。Spring Cloud Contract 不仅可以从契约生成存根,还可以生成测试。那意味着开发人员只需要定义契约,而其他的东西都会为生产者自动生成。这曾是我们希望做出的一个非常重要的决策,因为 CDC 的本质就是,假定生成的存根是可信的。如果有人在契约中定义了一个可以通过GET方法访问的端点/foo,那么在生产者一端,我们就可以通过向/foo端点发送GET请求来生成一个测试。如果没有这样的端点,那么测试就会中断,存根也不会生成。

显而易见,Spring Cloud Contract 与 Spring 环境集成得很好。我们已经支持使用 Spring Integration Spring Cloud Stream Spring AMQP Apache Camel 进行消息传递。但是,是一个叫做 Stub Runner 的组件让 Spring Cloud Contract 成为一个有吸引力的选项。我已经提到过,存根是从契约生成的。在默认情况下,我们希望用户以 JAR 文件的形式将生产者存根和契约发布到 Maven 库。假如存根的组 ID 为“org.springframework”,工件 ID 为“spring-boot-application”。为了运行存根,消费者需要像下面这样给测试加上注解:@AutoConfigureStubRunner (ids={'org.springframework:spring-boot-application:+'}

实际情况是,框架会自动下载包含存根的“org.springframework:spring-boot-application” JAR 文件的最新版本,然后启动一个内存内 HTTP 服务器,并在一个随机端口上提供存根。也就是说,只需一条注解,你就可以为构建生成整个环境的存根!此外,真正有趣的是,Spring Cloud Contract 可以完全消除服务发现工具。那意味着,存根注册在一个服务注册中心的内存版本中。那样,你可以像使用服务发现那样,向一个真正的 HTTP 服务器发送一个真正的 HTTP 请求。

如果你想要在测试环境中对打包好的应用程序执行一些冒烟测试,Spring Cloud Contract 的 Stub Runner 也非常方便。下载好的存根可以注册到真正的服务发现工具中(例如 Eureka ),在契约中定义的真正的消息可以发送给真正的队列(例如 RabbitMQ )。那样,你的应用程序甚至都不知道它在同存根交互。

InfoQ:消费者驱动契约模式,如果有的话,对端到端测试有什么影响吗?

Grzejszczak:这是一个很好的问题。就像我提到的那样,使用微服务增加了测试和部署应用程序的复杂度。尤其是,部署和端到端测试的组合很有趣。假如我们的系统由 50 个微服务组成,让我们提几个问题:

  1. 对于每个构建的微服务,每个团队都应该有它的部署环境吗?
  2. 谁来承担那 50 个环境的费用?
  3. 如果我们决定,不是每个微服务一个环境,那我们该如何处理部署队列?如果端到端测试需要运行很长时间,我们就不得不在轮到我们之前等待很长时间……
  4. 那些环境应该包含其他 49 个微服务的生产版本还是开发版本?
  5. 或者,生产版本和开发版本都应该测试?谁来配置那些环境,谁又负责维护那些环境?
  6. 有时候,企业无法在测试环境中使用生产数据——他们会对数据进行模糊处理,并满足完整性需求。

此外,还有一点需要考虑,就是端到端测试相当脆弱。有许多和代码 Bug 无关的原因可以导致它们失败。我不是说端到端测试没有带来任何价值——恰恰相反。当复杂度达到一定程度时,必须计算成本和收益。消费者驱动契约可以解决问题。如果消息违反了契约,那么执行契约测试可以提早终止构建。换句话说,如果你的消息中有错误,那么最好在构建的第一分钟就失败,而不是在 2 个小时的端到端测试的最后一分钟。

这可能会引起争议,但在我个人而言,我认为,只要设置恰当,端到端测试就是多余的,完全可以省略。这需要满足三个条件:(1)进行契约测试;(2)监控关键性能指标并报警;(3)可以进行回滚测试,并构建到部署管道中。作为这种部署管道的例子,你可以检出 Spring Cloud Pipelines 项目。

InfoQ:给我介绍下新的 Spring Rest Docs 集成吧,它是否可以改变传统的消费者驱动契约工作流?

Grzejszczak:那不新了,不过,它确实获得了更多的关注。有些用户不喜欢编写 Groovy DSL,不希望生成测试。他们希望完全属于自己的测试流程。还有一些其他的用户已经在使用 Spring Rest Docs 测试他们的代码。Dave Syer 就是其中的一位用户,向 Spring Rest Docs 添加 Spring Cloud Contract 集成就是他的主意。多亏了这个,你才能编写测试来测试你的 Web 应用程序以及自动生成存根。使用 Spring Cloud Contract 的最新版本,你还可以从 Spring Rest Docs 生成 Groovy DSL 契约。

至于工作流,我可以想象得到,消费者和开发者结对满足消费者需要的测试和存根。那样,流程得以保留。另一方面,有些事情告诉我,Spring Rest Docs 方法将更多地应用在“生产者契约”方法中。生产者定义契约是什么样子也是如此。在 Spring,我们喜欢用自己的产品来进行开发,Spring Initilizr(start.spring.io 背后的代码)已经使用了 Spring Cloud Contract,而且,Spring Initilizr 存根发布到了 Spring 的 Maven 库。

InfoQ:最后一个问题,在你们的路线图上,有什么有趣的东西可以介绍一下吗?

Grzejszczak:我们刚刚发布了 Spring Cloud Contract 的最新版本“1.1.0.RELEASE”,带来了一些有趣的特性,其中包括完全模块化(现在,你可以自定义 Spring Cloud Contract 的部件,比如,生成 PHP 测试),所以,在接下来的几个周里,我们最可能做的是修复 Bug,让 API 更稳定。就长远规划而言,我们在考虑简化非 Java 用户的工作。不过显然,对我们而言,最重要的是用户的反馈,我们会调整规划满足他们的需求。

如果你想进一步了解这个项目,可以查看项目主页。如果你有什么问题,可以通过 Gitter 或者 Twitter( @mgrzejszczak )联系我。

查看英文原文 Q&A with Marcin Grzejszczak on Spring Cloud Contract

2017-04-27 19:003147
用户头像

发布了 1008 篇内容, 共 390.9 次阅读, 收获喜欢 344 次。

关注

评论

发布
暂无评论
发现更多内容

LeetCode刷题13-简单-罗马数字转整数

ベ布小禅

9月日更

找啊找啊找工长,找到一个好工长

escray

生活记录 9月日更

cxx 的枚举类型

hedzr

c++ 算法 枚举

【LeetCode】二叉搜索树的后序遍历序列Java题解

Albert

算法 LeetCode 9月日更

看懂这个故事,轻松实现从技术到管理的华丽转身!

博文视点Broadview

打分吧!客服小姐姐,评分页面与客户总分页面的 Django 实现

梦想橡皮擦

9月日更

HTTP系列之:HTTP缓存

程序那些事

缓存 Netty HTTP 程序那些事

epoll底层实现源码及epoll反应堆模型

hanaper

linux网络包收发讲解

赖猫

Linux

08. 语音识别与第二次AI热潮

Databri_AI

人工智能

Go 专栏|开发环境搭建以及开发工具 VS Code 配置

AlwaysBeta

Go 语言

Vue进阶(八十九):watch 用法详解

No Silver Bullet

Vue 9月日更

C语言:十进制、十六进制数据互换

不脱发的程序猿

C'语言 进制转换

在线JSON转Mongoose工具

入门小站

工具

JavaScript数组常用的方法总结

孙叫兽

JavaScript 大前端 数组 引航计划

C语言:十进制、BCD码互换

不脱发的程序猿

C语言 十进制、BCD码互换

Linux之lastb命令

入门小站

Linux

前端开发css这些样式你还熟悉吗,Chrome是必备技能

你好bk

CSS html css3 大前端

JDK 8 及其后续 JDK 中 Period 和 Duration

HoneyMoose

LeetCode题解:143. 重排链表,数组,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

Java中高级核心知识全面解析,Java工程师需要掌握的技能

Java 程序员 后端

Java全面学习视频书籍,阿里架构师看到都觉得好,Java自学教程

Java 程序员 后端

【LeetCode】所有奇数长度子数组的和Java题解

Albert

算法 LeetCode 9月日更

Excelize 开源五周年 🎉

xuri

Excel Excel数据分析 Go 语言 Excelize

架构实战营模块七作业

老猎人

架构实战营

粗放生长时代结束,高精地图收紧灰色地带

脑极体

网络攻防学习笔记 Day123

穿过生命散发芬芳

9月日更 互联网安全 流量采集

架构实战训练营|作业|模块2

Frode

#架构实战营

IntelliJ IDEA 如何快速查看提交代码的对比

HoneyMoose

【Flutter 专题】59 图解 Android Native 获取 Flutter 资源文件

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 9月日更

活动回顾 | Apache Hudi x Pulsar Meetup 杭州站(戳进看视频)

Apache Pulsar

阿里云 Apache Pulsar StreamNative

Marcin Grzejszczak访谈:Spring Cloud Contract_Java_Andrew Morgan_InfoQ精选文章