为什么在服务器和客户端之间共享接口是一个坏主意?


12

当我发现一种在HTTP服务器与其客户端之间共享接口的方法时,我正在阅读Spring Cloud Netflix文档。他们将这个示例用于微服务,尽管没有理由不能将其扩展到通用HTTP通信:

// The shared interface, in a common library
public interface UserService {
    @RequestMapping(method = GET, value = "/users/{id}")
    User getUser(@PathVariable long id);
}

// The controller, on the server
@RestController
public class UserResource implements UserService {
}

// The same interface used for the client
@FeignClient("users")
public interface UserClient extends UserService {
}

这定义了一个既用作服务器(Spring @RestController将其转换为HTTP服务器)又用作客户端(Feign @FeignClient将其设置为供HTTP客户端使用)的接口。服务器和客户端类的实现可以在单独的项目中使用,但仍使用相同的接口来确保类型匹配。

但是,在示例下面,他们提出了以下警告:

注意:通常不建议在服务器和客户端之间共享接口。它引入了紧密耦合,并且实际上也不能以当前形式与Spring MVC一起使用(方法参数映射不被继承)。

好的,所以它目前尚未很好地集成在一起……但是,在警告共享代码以及在服务器和客户端之间引入耦合的警告之后,他们认为这很重要。他们为什么认为以这种方式共享接口是一个坏主意?

没有它,您将无法保证服务器和客户端彼此发送它们都可以理解的数据。您可以将一个字段添加到一个字段中,但不能添加另一个字段,并且只能发现不匹配,直到运行时。在我看来,它不是在引入耦合,而只是揭示已经存在的耦合。使服务器完全独立的需求是否比让服务器知道它们将接收什么类型的数据更大?


1
就客户端/服务器处理的数据/格式而言,存在的耦合由协议决定-可以用作约定的一部分文档。通过共享接口引入的耦合是编译时耦合-考虑更改接口时发生的情况(例如,以向后不兼容的方式),但是使用该接口的客户端/服务器代码在不同的时间部署。这种部署时耦合也很难管理,特别是在Netflix的规模。
Castaglia '16

1
我敢肯定我不是在Netflix的规模上运作:)但是,如果以向后不兼容的方式更改了接口,那么这不只是将错误从编译时发现转换为运行时发现吗?他们认为在缓慢升级所有服务器时让一些函数调用失败是否可以?
本S

1
可能 取决于客户端代码。还考虑另一种情况:首先升级服务器,现在客户端必须处理(意外地)失败的呼叫...
Castaglia

1
很好奇,通过共享此接口,它是否限制了您可以使用哪种语言/堆栈来构建客户端?
JeffO

是的-这是一个Java文件,因此您必须使用Java。您也许可以使用其他JVM语言,但我还没有尝试过。
本S

Answers:


6

注释中所述的原因是,它导致客户端平台与服务器平台紧密耦合。在这里,这意味着您的客户需要使用服务器上使用的语言/平台,以了解服务器的预期合同。请注意,共享相同代码(特定语言/平台的工件)和达成特定合同之间存在差异。

相反,许多项目使用文档作为合同。示例请求和响应以标准协议(例如REST)为中性格式(例如JSON)。(例如,请参阅Stripe API文档)。因为为您可能要使用或允许的每个可能的客户端平台编写基于代码的合同是不切实际的。还有一些人使用API​​管理工具来定义中立合同

您添加字段的示例是一个单独的问题-一个示例,说明为什么它对版本API合同很重要。让客户使用他们设计的版本。向后不兼容的新API版本与旧版本并存。旧版本的客户端将继续工作,直到其团队进行更新或直到您淘汰旧版本为止(在弃用/迁移期之后)。请参阅并行更改

遵循(中的隐含建议)警告可以帮助客户端和服务器以对每个客户端和服务器有意义的方式和步伐发展。如果可以合理地保证服务器和客户端将始终共享相同的语言/平台并以相同的速度发展,则可以使用特定于语言和平台的代码工件作为合同将是可以的。但是,这可能不是一个合理的期望,尤其是对于针对Netflix OSS的项目(专门针对云可扩展性和性能的项目,具有所有必需的复杂性)。


2
是否真的希望客户端使用该接口?我一直认为这样的构造可以简化编写客户端的方式。毕竟,您仍然可以使用其他语言编写REST客户端。
吉米T.

1
确切地说,api仍然会存在,带有其路由定义,没有任何东西会阻止使用另一种语言创建客户端,但是只要您使用java就能使用该接口
Leonardo Villela
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.