前言
在今天,OpenAPI 的应用已经越来越广泛,尤其是开放服务和云计算领域中。作为“集成”或者“被集成”的主要实现方案,今天的应用研发中,很少没有涉及到 OpenAPI 的使用的。那么对于一个开发者而言,使用 OpenAPI 的主要方式自然是 SDK,如果一个 OpenAPI 服务没有提供对应语言的 SDK,那么使用它之前的第一件事情便是写一个对应的 SDK。
为 OpenAPI 编写 SDK 通常而言并不是一件困难的事情,无外乎是熟悉 OpenAPI 的参数,封装成 Client 对象后,调用底层 HTTP 库,进行发送和处理返回数据,与前端的 AJAX 调用没什么两样。因此通常情况下要完成一个 SDK 的编写,并不是什么难点。但是,如果作为一个云计算厂商,提供令客户满意的 SDK 并不是一件容易的事情,因为在云计算厂商下,我们面临着更复杂的情况:
-云计算厂商的产品线多,每一个产品线的 SDK 不一定能被别的产品线所重用。
-云计算厂商的客户分布广泛,我们的客户使用任何编程语言的可能都存在。
以阿里云的产品为例,它一共有上百个产品,如果我们要支持到 10 门编程语言的客户,那就不是一个 SDK 的事情了,它是上千个 SDK 的事情。任何事情一旦上规模,它都不再是简单的事情。
SDK 研发的挑战
在云计算厂商的 SDK 研发中,我们的挑战主要有如下这些:
-由于涉及到的编程语言众多,能支持到的语言数量有限,即使支持了某门语言,并不一定完全地照顾到了该语言下的开发者习惯。
-来自众多产品线的挑战,语言数乘以产品数,这是一个规模化带来的挑战。支撑这么大规模的 SDK,所需要的人力成本不低。
-即使支持到更多的语言,更多的产品,那么随之而来的维护成本也是一个巨大的成本。
-为了保障维护的过程不带来返工问题,质量保障的工作也少不了,同时支持多语言、多产品的质量保障,是不小的挑战。
-SDK 的工作不仅仅是代码本身,涉及相关的文档、代码示例等,对应的支持工作亦是不小的工作量。
最终,这些工作都是一脉相承的,因此一致性是最大的挑战,如何保障语言间、产品间、文档等一致,是云厂商 SDK 研发中最大的挑战。
多语言的挑战
在过去,一些开放平台主要会公布一些 OpenAPI 的文档,必要的签名算法,以及 1 - 2 门主流编程语言的 SDK。其余的编程语言下的 SDK 通常是交给用户或者生态环境下的其他开发者来完成。但从阿里云的工单历史里,我们发现大量的 OpenAPI 的使用问题,及社交网站上的吐槽,这迫使我们重新审视如何为开发者提供更好的 SDK。
当一个开放服务越知名,它的用户量及用户种类就会越多。比如早年的FaceBook、Twitter、微博等社交网站的OpenAPI,通过OpenAPI催生了大量的第三方的应用,因此可以说 OpenAPI是刺激生态成熟的关键因素。但作为平台方的编程语言技术栈仍然是有限的,不太可能非常好的支持好所有编程语言的开发者。
不同的编程语言给平台方及开发者带来的困难主要体现在如下两个层面上:
1.开发者不一定能正确实现平台方给定的签名算法等客户端要求
2.即使是平台方正确实现了客户端的要求,但编码风格并不符合编程习惯。
对应的主要表现如下:
1.客户端要求
一般而言,平台方制定了 OpenAPI 的接入方式,开发者需要按照文档所描述的算法,来进行客户端的编写。以 ECS 的接入文档为例:https://help.aliyun.com/document_detail/25488.html ,这里最复杂的莫过于签名算法的部分。
按照道理,每个开发者都有一定实现签名算法的能力,但事实是大部分的开发者都是工具、库、框架的使用者,日常的工作也大部分以接触业务为主,一些涉及底层的点并不是特别擅长。这部分工作就像一道门槛,将编码能力稍弱的开发者挡在门外。即使有部分开发者能够正确实现这些客户端要求,但实现得也不一定完整或准确,因此我们经常收到一些签名算法不准确的工单。
但作为平台方,也不太可能支撑到所有的编程语言,总是有部分疏漏存在,这是云计算厂商在SDK支撑上的痛点所在。因为这种复杂性,我们尽量推荐开发者使用官方维护的SDK或者成熟的三方SDK,尽量避免自己从头尝试签名算法来完成一个自己的SDK的研发。
2.编程社区习惯
云厂商在面对多编程语言的另一个挑战在于,即使作为平台方,非常熟悉客户端所需要的实现细节,能把 SDK 的内在部分准确实现,但依然很难保障 SDK 的其他部分是符合当前编程语言的编码风格和开发者习惯的。
比如我们曾经面临很多吐槽说我们 Python SDK 写得极像 Java 代码(因为确实是 Java 的同学编写的)。作为平台方,诚然在公司的范围内,有来自不同语言栈的程序员可以支持到不同语言 SDK 的编写,但仍然是有限的。作为 OpenAPI 的平台方其实更多的工作是要关注 OpenAPI 的参数、文档,以及网关的稳定性,大多数情况是某个语言的开发者兼职提供了另一门语言的 SDK。
除了上面的问题外,还有人员层面的挑战。OpenAPI 的重头工作是平台及背后业务的实现,从历史来看,专职负责 SDK 及相关工作的团队是非常少的,直到云计算被广泛应用(AWS 和 Azure 有人数不低的 SDKs & Tools 团队)。相比于社交网络的开放平台,云计算厂商的 OpenAPI 则跟客户的资源,甚至说钱紧密相关,因此专门的团队是有必要的。
一个优质的 SDK,一定是要非常熟悉该门编程语言,也非常熟悉业务的开发者,结合编程语言及业务之间的最佳实践,才能产出。我们的现状是熟悉业务的同学,不一定对开源社区熟悉,主要的工作方式是寻找团队中比较擅长某门编程语言的人来完成该语言的 SDK,因此整体要覆盖到较多编程语言的话,需要投入的人力是不小的成本。
多产品的挑战
除了多种编程语言带来的挑战外,与普通的开放平台相比,云厂商的情况要复杂得多,因为它的产品线非常之多。如果光看产品数量的话,阿里云有上百个云产品,如果同时支持8-9门编程语言,这个 SDK 的数量就非常庞大了,它是一个至少上千的数量级。幸运的是,网关发挥了很大的作用,每个产品不需要重复地研发自己的网关部分,统一网关能帮助云产品解决大量的通用问题,因此网关会将上百个产品收敛为几种网关产品。
每种网关下的 OpenAPI 都有自己独特的部分,需要特殊处理。更比较遗憾的是,因为历史原因,这些 OpenAPI 都不是 RESTful 风格的,在社区应用最广泛的 Swagger 工具体系在这里根本无法应用起来。因此我们不得不为每种网关去研发它对应的核心 SDK,也就是说,我们为了支持不同的网关,不得不重复地进行一些基础的研发。
可维护性的挑战
接着说维护的挑战。
即使社区来了一个某编程语言的大牛,根据我们的文档编写了一个非常符合该开发者社区习惯的 SDK,用户用起来都觉得不错。但是,某天 OpenAPI 发生了一些改变后,会发生些什么?
作为 OpenAPI 平台方,需要修改 OpenAPI 后端实现,然后再修改文档;开发者发现文档发生改变了,再根据文档,对之前编写的 SDK 进行更新。暂且不说 OpenAPI 的更新会不会带来兼容性的问题,也不说 SDK 更新后是否带来兼容性问题,只说这样的维护方式,它是非常低效的。
这里的痛点在于 OpenAPI 没有彻底的开放。云厂商通过文档的形式开放的 OpenAPI,并不是一个结构化的数据,导致 SDK 的维护工作成为一个人工的工作。即使大牛的代码写得再好,常年累月地义务手工维护,总有失去耐心的一天。
质量的挑战
延续维护的话题,一旦涉及 OpenAPI 的改动,或者 SDK 的改动,我们需要考虑的事情是改动是否会导致客户更新后,程序无法运行,或者在某个时候突然出现 Bug。在前文我们提到“官方”或者“成熟” SDK 的说法,并不是说不鼓励开发者去尝试自己编写 SDK,而是在企业应用中,我们对质量是有更高的要求的。我们不仅仅是编写完主要的代码,就可以提供给客户使用了,我们需要确保提供的 SDK 是有质量保障的,能在生产环境正常运行的,而不是一个只能跑 demo 的玩具。
保障 SDK 的质量有两个层面,一个是基本的 SDK 的功能;一个是涉及到 OpenAPI 自身业务逻辑的保障。
基本的 SDK 的功能指的是 OpenAPI 业务无关的那部分,比如签名算法。这部分工作我们可以依靠单元测试及测试覆盖率工具来保障它的质量。
涉及到 OpenAPI 自身业务逻辑的部分,理论上不是客户端要考虑的,因为 OpenAPI 的逻辑的变更及扩展性,通常与客户端的关系不大。但仍然需要考虑的是通过集成测试的方式来做基本的保障。
对 SDK 做质量保障并不是一件比较难的事情,通用的测试方法都能做到一定的质量保障。挑战在于同时有那么多的编程语言和那么多的产品。因此不光是产品 SDK 数量众多,为了保障这些 SDK 的质量,所涉及的测试工作也不少。
这部分工作对于云计算厂商而言的痛点在于 OpenAPI 的测试要在不同的编程语言之间重复编写及维护,是一个量级不小的挑战。
做好质量保障是能得到一些收益的。这里有个小小的例子。
我们的网关在做鉴权时,通常对签名字符串和 Access Key Secret 以某种签名算法进行签名,在服务端则验证这个签名值是否匹配。我们注意到工单里出现不少签名错误的情况,这导致我们无法判断客户是否是用了自己的签名算法,还是单纯的输错了 Access Key Secret。
总的来说,签名及鉴权的公式如下:
f(sign_str, access_key_secret) = sign
// f 是签名算法
这里面的因子有 3 个,签名算法 f、sign_str、access_key_secret。当出现签名不匹配时,出现错误的原因一定是三者之一。因为签名失败时,服务端会返回它得到的 sign_str ,后来我们加入了服务端 sign_str 和客户端 sign_str 对比的方式,可以排除是 sign_str 拼接的问题。因为有足够的测试,我们可以验证我们的签名算法 f 是一定正确的。因此最后有问题的是 AccessKeySecret 没有填对。
借助测试,我们将出现签名错误时的模糊提示,精确到客户是否填入了正确的 AccessKeySecret,并改进错误提示,避免客户及客服人员面对错误时的手足无措,进而降低工单量。
文档/Demo
文档和 Demo 其实仍然是可维护性的挑战。当一个 SDK 被产出,那么必然有相关的文档或 Demo 来介绍它。我们面临的一个问题是,大多数的云产品最多只有少量编程语言的 demo 介绍,无法覆盖到很多的编程语言,而且这些 demo 大多是通过手工来编写的。这些 demo 被编写出来的较短时间里是能正常工作的,但时间一旦过去,很难保证这些 Demo 是否还能运行。
作为云厂商,所面临的问题就是,Demo 的完整性,Demo 的有效性。
一致性的挑战
最后说到一个最关键的问题,那就是一致性问题。一致性是一个涵盖很广的考量面,这里关注的有如下这些:
-OpenAPI 与 SDK 之间是否参数保持一致
在产品与产品之间,风格是否保持一致
-相同产品的不同语言客户端之间,行为是否保持一致,它们的测试是否保持一致
-OpenAPI 与文档之间内容是否保持一致
-SDK 与文档之间是否保持一致
上面这些地方只要有一个点出现了不一致的状况,都可能导致用户在使用 SDK 调用 OpenAPI 时出现意想不到的坑。
前文提到,在多语言的情况下,为了开发者习惯,保留适合当前编程语言的特征是有必要的。但用户在审视阿里云的所有 OpenAPI 或者 SDK 的时候,会认为它们是应该一样的,应该是一致的。
这里有一个小例子。我们的客户使用了资源编排解决方案,即 Terraform。在接入的过程中,用户希望使用一种特殊的 Credentials 方式,但最后发现,有几个产品的 SDK 没有支持到这种方式,导致接入过程受到影响。
完美的 SDK 是怎样的?
上文提到那么多的问题,其实归结起来,我们希望要的是一个这样的 SDK:
-是由某门编程语言的大神来负责编写的 SDK,它能照顾到这门编程语言的开发者习惯。
-SDK 的内在功能特性,和制作流程是一致的。即使在不同的编程语言之间,即使在不同的网关和产品之间。
-OpenAPI 的定义数据是开放的,可以通过自动化的方式生成出来 SDK,因此维护起来非常。
-一个 OpenAPI 的测试代码可以只编写一次,但可以在不同语言的 SDK 下运行。
-SDK 的文档和 Demo 能和 OpenAPI 定义之间保持同步更新。
后面的主题讨论中,我们将深入介绍解决方案,如何以合适的团队及技术方案来迎接上述的挑战。欢迎大家持续关注我们的分享!