Better Code: 关于接口的灵活性
在实际需求开发中,我们会面对复杂多变的需求。所以在给外部提供API的时候,经常会面临接口协议的变更:例如增加一个查询字段,支持按照某个字段升降序,或者多返回某个字段。
此时你也许会想,不如直接支持graphql或者类似的语法,将整个模型暴露出来,想要什么字段,根据什么排序,查询多少数据量,按照什么升降序自己决定好了。这样能做到一次开发,多次使用,一劳永逸。
但是,这往往是过于理想化的考虑,特别是对于大部分项目,或者被非常多外部系统依赖的服务(这也是为什么需求变更比较多的原因)
在实际开发中,我们都知道,一个接口一旦上线生产,那么协议变更就变得非常难,至少要非常谨慎。因为有众多的依赖方。并且下线一个接口也尤为困难,因为势必要推动所有系统切换新接口。
所以,如果暴露整个模型由调用方自行选择,那么结果就是,将主动权交给了调用方,把自己变得被动。因为你很难感知到调用方是如何组合那些条件的,用了哪些参数,是否合理。模型层面的变更将变得困难,字段的增删,类型变更,格式变更等等都需要考虑诸多调用方。
相当于拿一时的便利,换取了未来维护的不确定性。但是,确定的是,维护成本是成倍地上升。
假设模型数据变得庞大,从几千增长为十万级,百万级,那么原先很多无关紧要条件变得棘手,例如按照一个不确定的字段排序,或者一个不在索引中的字段排序。此时原先的查询变得很慢,数据库压力变大,机器负载上升。
那么,这时候要保证系统正常,就会付出更大的代价。
这个可不是提供一个/api/v2
那么简单,大部分系统一旦使用,除非特别的原因,否则是不会考虑迁移新接口的,此时,可能由于某几个很小的系统调用吃掉系统绝大部份的资源。举步维艰。
所以,在接口协议设计和提供的时候,需要花更多的时间去思考,始终保持谨慎,克制。
比如,需要一个字段,绝不提供两个。协议中可选的内容,都是已确认可控的内容。消除不确定性。
这或许看起来接口不够灵活,不够强大。但是,消除了不确定性。
应该在内部实现保持灵活,但暴露出去的保持克制。例如某些地方可以变成可配置的,需求变更只需要改配置而不是代码。
即,灵活性始终把握在自己手中。应对需求变更的时候,付出少量的时间。相对原先绝对灵活的方式会多出一些确认及开发的时间,但是对于未来的维护时间,这已经是非常划算的了。
内部支持,谨慎提供。 make everything under control
如果调用方可控,例如前后分离自己的前端或者同一个系统内的上层服务,那么用graphql 或者类似灵活的方式提供接口问题不大,毕竟变更或升级的成本不高,比较可控。
否则,提供接口不要那么奔放。
另外,最近遇到一个问题得到一个小的tip,如果一个接口需要提供两种或两种以上有差异的返回(协议有差别,但是不是特别大),建议提供多个接口而不是在一个接口通过参数动态确定返回。即使差异非常小。差异小只在当下,随着时间推移需求变化,耦合在一起的代码将会维护困难,改一个逻辑可能动到不相关的返回。宁可多写一些代码,尽量保持逻辑独立性。