朱赟的技术管理课_19_18_每个工程师都应该了解的API_的设计和实现
你好,我是朱茵。
今天我分享的主题是每个工程师都应该了解的API的设计和实现。
在一个初创公司成长的过程中,作为工程师的你,也许常常会遇到下面这样的情况。
有一天,你看到一段代码或一个算法,觉得这些代码不大,经得起推敲。
于是你用gate blame命令去寻找代码的主人,结果发现原来作者是如今早就不写代码的CTO或VP之后,在一个偶然的机会里,你和他讲起这件事,他就会自豪的告诉你哦,那时候我们必须在一天之内做出这个产品特性。
当时也就我一个程序员吧,一天的时间,这是当时能做出最好的方案了。
说完,他便陷入了对美好时光的怀念里。
你也可能听说过这样的故事。
有一天你的CTO突发奇想,行云流水的提交了一段代码,大家一看很激动啊,很多人跑去观摩大神的代码,结果觉得问题多多,于是在PR上提了一堆评论。
Cto一看有点傻眼了,几十条评论,随在代码要这么写啊,好麻烦。
他就和一位工程师说,你把评论里的问题解决下,合并到主分支吧,然后就开开心心的,该干嘛干嘛去了。
开篇讲的这两个小故事是想说明一个道理,一个公司早期的代码会因为各种历史原因不是那么完美,但是在特定的时间点,这就是当时最优的方案。
随着公司的发展,成品功能不断叠加,代码架构不断优化,系统会经历一些从简到繁于后,再由繁到简的迭代过程,代码的改动也会相当巨大。
也许有一天,你会几乎不认识自己当初的作品了。
Api的设计和实现更是如此,在我们的工作中,很少能见到。
Api的设计和实现从最开始就完美无瑕疵一套成熟的API,很多时候都是需要通过不断演化迭代出来的。
今天我就和你聊聊API的设计和实现。
首先第一点,我们先从API的签名说起。
Api的签名,API的签名或者叫协议,就是指API请求和响应支持哪些格式和什么样的参数。
首先做过API的人都知道,一个上线使用的api再想改改的签名会,因为兼容性的问题痛苦不堪。
因此,API签名的设计初期一定要经过反复推敲,尽量避免上线后的改动。
除了一些基本的restful原则外,签名的定义很多时候是对业务逻辑的抽象过程,一个系统的业务逻辑可能错综复杂。
因此,API设计的时候,就应该做到用最简洁直观的格式去支持所有的需求。
这往往是API设计中相对立的两面,我们需要找到平衡。
有时候,为了支持某一个功能,似乎不得不增加一个很违反设计的接口。
而有时候,我们为了保证API绝对规范,又不得不放弃对某一些功能的直象支持。
这些功能只能通过迭代调用或客户端预处理的方式来实现。
这种设计上的取舍,通常会列出所有可行的方案,从简单的设计到繁杂的设计,然后通过分析各种使用实例的频率和使用某种设计时的复杂度。
从实际的系统需求入手,尽可能让常用的功能得到最简单直接的支持。
还有一定程度上牺牲一些极少用到的功能,反复考虑系统使用场景,尽可能获得一个合理的折中方案。
Api的设计原则。
在这个折中的过程中,我们需要始终保证满足这些基本原则。
一、保证API百分之百restful. Restful的核心是everything is a restce,所有的行为和接口都应该是相应resource上的增删改查操作。
如果脱离这种设计模式,一定要再三考虑是不是必要在没有其他方案,可以一免破坏restful风格。
二、在请求和响应中应该尽可能的保持参数的结构化。
如果是一个哈希,就传一个哈希。
Api的序列化和反序列化机制会将其自动序列化成字符串,以语言之间的API,比如ruby、 java、 c sharp之间的调用,通常都是在序列化和反序列化机制中完成不同语言间类型的转换。
三、安全的考虑始终应该放在首位,保证对特定的用户永远只暴露相关的接口和权限。
可以使用证书和白名单,也可以通过用户登录的证书生成验证票据或者session、 cookie等方式来处理。
此外,所有的API层的日志要保证不记录任何敏感的信息。
四AP本本应该是客户端无关的。
也就是说,一个api对请请求的处理,尽可能避免对客户端是移动端还是网页端的考虑,客户端相应的响应格式不应该在API中实现。
所有的客户端无关的计算和处理,要尽可能在服务器端统一处理,以提高性能和一致性。
五、尽可能让API是幂等的。
关于幂等可以参考我之前写的聊聊幂等一文。
这里面有几个不同层次的含义,举例说明同一个请求发一遍和发两遍,是不是能够保证结果相同?请求失败后重发和第一次发是不是能保证相同结果?当然,要不要做成幂等,具体的实现还要看具体的应用场景,使用好API框架。
每个语言都已经提供了很好的API框架。
你需要在设计前先多了解这些框架。
如果你是个小团队,资源没那么充分,选一个合适的框架入手,适当调整,比从零开始造轮子要好得多。
等公司长大了。
由于各自业务逻辑的特殊需求,最终都会定制一套自己的API.实现方案评估一个API框架可以从以下几个方面考虑,一对访问权限的统一控制。
二、自动测试的支持。
三、对请求和响应的格式以及序列化和反序列化的支持。
五、对日志和日志过滤的支持。
五、对自动文档生成的支持。
六、对架构以及性能的影响设计中的平衡API设计中存在很多对立的因素,比如简洁还是繁复,兼容性和效率,为现在设计还是为未来打算等等。
根据自己的工作实践,我给出以下观点供大家参考。
一、自由总是相对的,就好像在一个群体里,如果没有规则,完全行为自由,就会出现各种问题,小群体还好。
而对于一个大群体,有人就会被别人的自由误伤。
写软件也是一样。
一个小的创业公司里,API怎么设计代码怎么写?几个人一协商达成共识,并不需要那么多的条条框框,也照样行得通。
公司越大,代码协作的人越多个人的自由就会在设计和实现中产生问题,并导致最终的冲突。
所以很多大公司会制定一些api的最佳实践,强制要求设计和实现中必须按照某种模式来做。
有些规则虽有道理,但也不是说不这样限制。
所以在很多时候,因为这样的规则,我们的API设计中会有很多限制。
这在表面上似乎给设计带来无谓的难度。
但是,仔细考量,从规范代码和设计一致性的角度而言,还是有很大好处的。
二、为当前设计还是为未来设计。
Api设计里很常见的一个情况,是一个目前并没有人使用的系统功能。
它的存在,只是因为有人提出这种情况,我们以后应该要支持。
所文中我曾讲过,由于API上线后再改很困难,所以在设计初期就要尽可能的考虑未来的发展。
但是这些可能的应用场景,因为需求的细节和使用频度都不明确,最容易造成系统的过渡设计。
我记得有一个API设计的经典原则,概括一下,就是要考虑未来的场景,在设计时留有余地,但永远只实现当前产品真正要用的功能。
三、可维护性和效率设计和实现里常常会有一些封装和抽象的概念。
这些特殊情况下,封装在分拆的过程可能会在一定程度上影响api的响应速度或者代码质量的优化和性能的优化上有冲突或个很难一概而论。
具体的做法要看代码是否在关键路径上,或者这段代码是不是需要多人协作等等。
最终的选择就要具体问题具体分析了。
四、是否采用AOP, AOP本身就是一个极具争议的话题概括。
说来,AOP的理念是从主关注点中分离出横切关注点,分离关注点,使得解决特定领域问题的代码,从业务逻辑中独立出来。
业务逻辑的代码中不再含有针对特定领域问题代码的调用。
业务逻辑同特定领域问题的关系,通过侧面来封装维护,这样原本分散在整个应用程序中的变动,就可以很好的管理起来。
因为API的设计和实现中有很多通用的关注点,如日志、解析、监控等等,所以API成了AOP一个很自然的应用领域。
使用AOP的api设计继承了AOP的优势,这样代码的重用性、规整性以及程序员可以集中关注于系统的核心业务逻辑等,但也会自然而然的继承了AO程系有的问题。
例如,代码的剖析和调试困难增加,如程序员的相关经验有更多要求,相互协作的要求也增强了。
比如改变某一个功能,可能会影响到其他的功能等等。
是否选择使用AOP和你的需求场景、人员、技能和设计复杂度息息相关,需要技术决策者根据具体环境做出判断。
今天我从两个小故事入手,和你讨论了API的设计和原则,内容分为四个部分,API的签名。
Api的设计原则使用现有编程语言的API框架,如何在API设计中取得平衡? Api设计是现代软件系统中不可或缺的一个环节。
不同的系统需求和不同的编程语言下API的设计都大不相同,但总有一些原则和注意事项是可以提取出来的。
今天我和你讨论的就是这些通用的原则,希望对你的实际工作有帮助。
最后给你留一道思考题,API的签名设计是语言无关的那你在设计中会引入更多的语言,还是更少的语言去实现不同的API呢?优点和缺点各是什么?期待你的回复,我们一起进步,下期再见。